Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dariah
dariahsp
Commits
ada0273c
Commit
ada0273c
authored
Nov 05, 2020
by
Gradl, Tobias
Browse files
10: Work with SAML attributes
Task-Url:
#10
parent
fb0687c7
Pipeline
#17635
passed with stage
in 1 minute and 54 seconds
Changes
9
Pipelines
1
Show whitespace changes
Inline
Side-by-side
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/authenticator/BaseProfileCreator.java
View file @
ada0273c
...
...
@@ -3,6 +3,7 @@ package eu.dariah.de.dariahsp.authenticator;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
eu.dariah.de.dariahsp.config.model.RoleDefinition
;
import
eu.dariah.de.dariahsp.model.ExtendedUserProfile
;
...
...
@@ -32,4 +33,25 @@ public abstract class BaseProfileCreator {
}
return
roles
;
}
protected
void
mapAndAssignRoles
(
ExtendedUserProfile
profile
)
{
if
(
this
.
canMapRoles
(
profile
))
{
// Determine applicable role definitions
Set
<
RoleDefinition
>
mappedDefinitions
=
this
.
getMappedRoles
(
profile
);
// Set applicable roles as Strings
profile
.
setRoles
(
mappedDefinitions
.
stream
()
.
map
(
mr
->
ROLE_PREFIX
+
mr
.
getRole
().
toUpperCase
())
.
collect
(
Collectors
.
toSet
()));
// Set maximum applicable level
profile
.
setLevel
(
mappedDefinitions
.
stream
()
.
mapToInt
(
RoleDefinition:
:
getLevel
)
.
max
().
orElse
(
0
));
}
}
private
boolean
canMapRoles
(
ExtendedUserProfile
profile
)
{
return
clientName
!=
null
&&
profile
.
getExternalRoles
()!=
null
&&
!
profile
.
getExternalRoles
().
isEmpty
()
&&
roleDefinitions
!=
null
&&
!
roleDefinitions
.
isEmpty
();
}
}
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/authenticator/LocalProfileCreator.java
View file @
ada0273c
package
eu.dariah.de.dariahsp.authenticator
;
import
java.util.Optional
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
org.pac4j.core.context.WebContext
;
import
org.pac4j.core.credentials.UsernamePasswordCredentials
;
import
org.pac4j.core.profile.UserProfile
;
import
org.pac4j.core.profile.creator.ProfileCreator
;
import
eu.dariah.de.dariahsp.config.model.RoleDefinition
;
import
eu.dariah.de.dariahsp.model.ExtendedUserProfile
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
...
...
@@ -27,26 +23,7 @@ public class LocalProfileCreator extends BaseProfileCreator implements ProfileCr
return
Optional
.
empty
();
}
ExtendedUserProfile
profile
=
new
ExtendedUserProfile
(
credentials
.
getUserProfile
());
Set
<
RoleDefinition
>
mappedDefinitions
;
if
(
this
.
canMapRoles
(
profile
))
{
// Determine applicable role definitions
mappedDefinitions
=
this
.
getMappedRoles
(
profile
);
// Set applicable roles as Strings
profile
.
setRoles
(
mappedDefinitions
.
stream
()
.
map
(
mr
->
ROLE_PREFIX
+
mr
.
getRole
().
toUpperCase
())
.
collect
(
Collectors
.
toSet
()));
// Set maximum applicable level
profile
.
setLevel
(
mappedDefinitions
.
stream
()
.
mapToInt
(
RoleDefinition:
:
getLevel
)
.
max
().
orElse
(
0
));
}
this
.
mapAndAssignRoles
(
profile
);
return
Optional
.
ofNullable
(
profile
);
}
private
boolean
canMapRoles
(
ExtendedUserProfile
profile
)
{
return
clientName
!=
null
&&
profile
.
getExternalRoles
()!=
null
&&
!
profile
.
getExternalRoles
().
isEmpty
()
&&
roleDefinitions
!=
null
&&
!
roleDefinitions
.
isEmpty
();
}
}
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/authenticator/SamlProfileCreator.java
View file @
ada0273c
package
eu.dariah.de.dariahsp.authenticator
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
org.pac4j.core.context.WebContext
;
import
org.pac4j.core.profile.UserProfile
;
import
org.pac4j.core.profile.creator.ProfileCreator
;
import
org.pac4j.saml.credentials.SAML2Credentials
;
import
eu.dariah.de.dariahsp.config.
model.RoleDefinition
;
import
eu.dariah.de.dariahsp.config.Attribute
;
import
eu.dariah.de.dariahsp.config.
SecurityConfig
;
import
eu.dariah.de.dariahsp.model.ExtendedUserProfile
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.extern.slf4j.Slf4j
;
@Slf4j
@Data
@EqualsAndHashCode
(
callSuper
=
false
)
public
class
SamlProfileCreator
extends
BaseProfileCreator
implements
ProfileCreator
<
SAML2Credentials
>
{
public
static
final
String
EXTERNAL_ROLES_MAPPED_NAME
=
"externalRoles"
;
private
final
SecurityConfig
securityConfig
;
public
SamlProfileCreator
(
String
clientName
)
{
public
SamlProfileCreator
(
SecurityConfig
securityConfig
,
String
clientName
)
{
super
(
clientName
);
this
.
securityConfig
=
securityConfig
;
}
@Override
...
...
@@ -29,26 +33,60 @@ public class SamlProfileCreator extends BaseProfileCreator implements ProfileCre
return
Optional
.
empty
();
}
ExtendedUserProfile
profile
=
new
ExtendedUserProfile
(
credentials
.
getUserProfile
());
this
.
assignExternalRoles
(
profile
);
this
.
assignAttributes
(
profile
);
this
.
mapAndAssignRoles
(
profile
);
return
Optional
.
ofNullable
(
profile
);
}
Set
<
RoleDefinition
>
mappedDefinitions
;
if
(
this
.
canMapRoles
(
profile
))
{
// Determine applicable role definitions
mappedDefinitions
=
this
.
getMappedRoles
(
profile
);
// Set applicable roles as Strings
profile
.
setRoles
(
mappedDefinitions
.
stream
()
.
map
(
mr
->
ROLE_PREFIX
+
mr
.
getRole
().
toUpperCase
())
.
collect
(
Collectors
.
toSet
()));
// Set maximum applicable level
profile
.
setLevel
(
mappedDefinitions
.
stream
()
.
mapToInt
(
RoleDefinition:
:
getLevel
)
.
max
().
orElse
(
0
));
private
void
assignExternalRoles
(
ExtendedUserProfile
profile
)
{
Attribute
externalRolesAttribute
=
this
.
getExternalRolesAttribute
();
if
(
externalRolesAttribute
==
null
||
!
profile
.
containsAttribute
(
externalRolesAttribute
.
getName
())
||
profile
.
getAttribute
(
externalRolesAttribute
.
getName
())==
null
)
{
return
;
}
try
{
@SuppressWarnings
(
"unchecked"
)
List
<
String
>
memberOfs
=
(
List
<
String
>)
profile
.
getAttribute
(
externalRolesAttribute
.
getName
());
if
(
memberOfs
.
isEmpty
())
{
return
;
}
if
(
profile
.
getExternalRoles
()!=
null
)
{
for
(
String
memberOf
:
memberOfs
)
{
if
(!
profile
.
getExternalRoles
().
contains
(
memberOf
))
{
profile
.
getExternalRoles
().
add
(
memberOf
);
}
}
}
else
{
profile
.
setExternalRoles
(
new
LinkedHashSet
<>(
memberOfs
));
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"Unable to map memberOf attribute to external roles of the profile"
,
e
);
}
return
Optional
.
ofNullable
(
profile
);
}
private
boolean
canMapRoles
(
ExtendedUserProfile
profile
)
{
return
clientName
!=
null
&&
profile
.
getExternalRoles
()!=
null
&&
!
profile
.
getExternalRoles
().
isEmpty
()
&&
roleDefinitions
!=
null
&&
!
roleDefinitions
.
isEmpty
();
private
void
assignAttributes
(
ExtendedUserProfile
profile
)
{
List
<
Attribute
>
mappableAttributes
=
securityConfig
.
getSaml
().
getSp
().
getMappedProfileAttributes
();
if
(
profile
.
getAttributes
().
isEmpty
())
{
return
;
}
for
(
Attribute
a
:
mappableAttributes
)
{
if
(
a
.
getMappedAttribute
().
equals
(
"id"
)
&&
profile
.
containsAttribute
(
a
.
getName
()))
{
List
values
=
(
List
)
profile
.
getAttribute
(
a
.
getName
());
if
(!
values
.
isEmpty
())
{
profile
.
setId
(
values
.
get
(
0
).
toString
());
}
}
if
(
profile
.
containsAttribute
(
a
.
getName
()))
{
profile
.
addAttribute
(
a
.
getMappedAttribute
(),
profile
.
getAttribute
(
a
.
getName
()));
}
}
}
private
Attribute
getExternalRolesAttribute
()
{
return
securityConfig
.
getSaml
().
getSp
().
getMappedProfileAttributes
().
stream
()
.
filter
(
a
->
a
.
getMappedAttribute
().
equals
(
EXTERNAL_ROLES_MAPPED_NAME
))
.
findFirst
().
orElse
(
null
);
}
}
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/config/AttributeConfig.java
deleted
100644 → 0
View file @
fb0687c7
package
eu.dariah.de.dariahsp.config
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
public
class
AttributeConfig
implements
InitializingBean
{
@Autowired
private
SecurityConfig
securityConfig
;
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
if
(
securityConfig
.
getSaml
()==
null
||
!
securityConfig
.
getSaml
().
isEnabled
())
{
}
securityConfig
.
getSaml
().
getSp
().
getAttributeConfig
();
}
}
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/config/SamlProperties.java
View file @
ada0273c
package
eu.dariah.de.dariahsp.config
;
import
org.apache.http.client.HttpClient
;
import
java.time.Duration
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.opensaml.saml.common.xml.SAMLConstants
;
import
org.pac4j.saml.util.SAML2HttpClientBuilder
;
import
eu.dariah.de.dariahsp.config.model.SamlSpConfigProperties
;
import
lombok.Getter
;
import
lombok.Setter
;
...
...
@@ -17,7 +10,7 @@ public class SamlProperties {
private
String
authorizerName
=
"saml"
;
private
final
KeystoreProperties
keystore
=
new
KeystoreProperties
();
private
final
MetadataProperties
metadata
=
new
MetadataProperties
();
private
final
S
p
Properties
sp
=
new
S
p
Properties
();
private
final
S
amlSpConfig
Properties
sp
=
new
S
amlSpConfig
Properties
();
@Getter
@Setter
public
class
KeystoreProperties
{
...
...
@@ -31,45 +24,4 @@ public class SamlProperties {
public
class
MetadataProperties
{
private
String
url
;
}
@Getter
@Setter
public
class
SpProperties
{
private
String
metadataResource
;
private
boolean
generateIfNotExists
;
private
int
maxAuthAge
=
3600
;
private
String
entityId
;
private
int
httpClientTimoutMs
=
2000
;
private
boolean
signMetadata
;
private
List
<
String
>
signingMethods
;
private
List
<
String
>
digestMethods
;
private
List
<
String
>
supportedProtocols
;
private
boolean
authnRequestSigned
=
true
;
private
boolean
logoutRequestSigned
=
false
;
private
boolean
wantsAssertionsSigned
=
true
;
private
boolean
wantsResponsesSigned
=
true
;
private
List
<
ConditionalAttributeSet
>
attributeConfig
;
// ------------------------------------------
// Custom getters for complex default values
// ------------------------------------------
public
List
<
String
>
getSupportedProtocols
()
{
List
<
String
>
p
=
supportedProtocols
;
if
(
p
==
null
)
{
p
=
new
ArrayList
<>();
p
.
add
(
SAMLConstants
.
SAML20P_NS
);
}
return
p
;
}
public
int
getMaxAuthAge
()
{
return
maxAuthAge
<=
0
?
86400
:
maxAuthAge
;
// One day
}
public
HttpClient
getHttpClient
()
{
SAML2HttpClientBuilder
httpClient
=
new
SAML2HttpClientBuilder
();
httpClient
.
setConnectionTimeout
(
Duration
.
ofSeconds
(
httpClientTimoutMs
));
httpClient
.
setSocketTimeout
(
Duration
.
ofSeconds
(
httpClientTimoutMs
));
return
httpClient
.
build
();
}
}
}
\ No newline at end of file
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/config/SecurityConfig.java
View file @
ada0273c
...
...
@@ -8,20 +8,14 @@ import java.util.ArrayList;
import
java.util.List
;
import
java.util.Optional
;
import
javax.servlet.ServletContext
;
import
org.pac4j.core.client.Client
;
import
org.pac4j.core.client.Clients
;
import
org.pac4j.core.config.Config
;
import
org.pac4j.core.credentials.UsernamePasswordCredentials
;
import
org.pac4j.http.client.indirect.FormClient
;
import
org.pac4j.saml.client.SAML2Client
;
import
org.pac4j.saml.config.SAML2Configuration
;
import
org.pac4j.saml.credentials.SAML2Credentials
;
import
org.pac4j.springframework.annotation.AnnotationConfig
;
import
org.pac4j.springframework.component.ComponentConfig
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.ComponentScan
;
...
...
@@ -62,9 +56,6 @@ public class SecurityConfig {
public
String
getDefaultLoginUrl
()
{
return
defaultLoginUrl
==
null
?
baseUrl
:
defaultLoginUrl
;
}
public
String
getDefaultLogoutUrl
()
{
return
defaultLogoutUrl
==
null
?
baseUrl
:
defaultLogoutUrl
;
}
@Bean
AttributeConfig
attributeConfig
()
{
return
new
AttributeConfig
();
}
@Bean
public
Optional
<
LocalUsernamePasswordAuthenticator
>
localUsernamePasswordAuthenticator
()
{
...
...
@@ -183,7 +174,7 @@ public class SecurityConfig {
private
SamlProfileCreator
saml2ProfileCreator
()
{
SamlProfileCreator
saml2ProfileCreator
=
new
SamlProfileCreator
(
saml
.
getAuthorizerName
());
SamlProfileCreator
saml2ProfileCreator
=
new
SamlProfileCreator
(
this
,
saml
.
getAuthorizerName
());
saml2ProfileCreator
.
setRoleDefinitions
(
roleDefinitions
);
return
saml2ProfileCreator
;
}
...
...
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/config/model/SamlSpConfigProperties.java
0 → 100644
View file @
ada0273c
package
eu.dariah.de.dariahsp.config.model
;
import
java.time.Duration
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
org.apache.http.client.HttpClient
;
import
org.opensaml.saml.common.xml.SAMLConstants
;
import
org.pac4j.saml.util.SAML2HttpClientBuilder
;
import
eu.dariah.de.dariahsp.config.Attribute
;
import
eu.dariah.de.dariahsp.config.ConditionalAttributeGroup
;
import
eu.dariah.de.dariahsp.config.ConditionalAttributeSet
;
import
lombok.Getter
;
import
lombok.Setter
;
@Getter
@Setter
public
class
SamlSpConfigProperties
{
private
String
metadataResource
;
private
boolean
generateIfNotExists
;
private
int
maxAuthAge
=
3600
;
private
String
entityId
;
private
int
httpClientTimoutMs
=
2000
;
private
boolean
signMetadata
;
private
List
<
String
>
signingMethods
;
private
List
<
String
>
digestMethods
;
private
List
<
String
>
supportedProtocols
;
private
boolean
authnRequestSigned
=
true
;
private
boolean
logoutRequestSigned
=
false
;
private
boolean
wantsAssertionsSigned
=
true
;
private
boolean
wantsResponsesSigned
=
true
;
private
List
<
ConditionalAttributeSet
>
attributeConfig
;
private
List
<
Attribute
>
mappedProfileAttributes
=
null
;
// ------------------------------------------
// Custom getters for complex default values
// ------------------------------------------
public
List
<
String
>
getSupportedProtocols
()
{
List
<
String
>
p
=
supportedProtocols
;
if
(
p
==
null
)
{
p
=
new
ArrayList
<>();
p
.
add
(
SAMLConstants
.
SAML20P_NS
);
}
return
p
;
}
public
int
getMaxAuthAge
()
{
return
maxAuthAge
<=
0
?
86400
:
maxAuthAge
;
// One day
}
public
HttpClient
getHttpClient
()
{
SAML2HttpClientBuilder
httpClient
=
new
SAML2HttpClientBuilder
();
httpClient
.
setConnectionTimeout
(
Duration
.
ofSeconds
(
httpClientTimoutMs
));
httpClient
.
setSocketTimeout
(
Duration
.
ofSeconds
(
httpClientTimoutMs
));
return
httpClient
.
build
();
}
public
List
<
Attribute
>
getMappedProfileAttributes
()
{
if
(
mappedProfileAttributes
!=
null
)
{
return
mappedProfileAttributes
;
}
mappedProfileAttributes
=
new
ArrayList
<>();
if
(
attributeConfig
!=
null
)
{
for
(
ConditionalAttributeSet
set
:
attributeConfig
)
{
mappedProfileAttributes
.
addAll
(
this
.
getAttributesFromSet
(
set
).
stream
()
.
filter
(
a
->
a
.
getMappedAttribute
()!=
null
)
.
collect
(
Collectors
.
toList
()));
}
}
return
mappedProfileAttributes
;
}
private
List
<
Attribute
>
getAttributesFromSet
(
ConditionalAttributeSet
set
)
{
List
<
Attribute
>
mappedAttributes
=
new
ArrayList
<>();
if
(
set
.
getAttributeGroup
()!=
null
)
{
for
(
ConditionalAttributeGroup
group
:
set
.
getAttributeGroup
())
{
mappedAttributes
.
addAll
(
getAttributesFromGroup
(
group
));
}
}
return
mappedAttributes
;
}
private
List
<
Attribute
>
getAttributesFromGroup
(
ConditionalAttributeGroup
group
)
{
List
<
Attribute
>
attributes
=
new
ArrayList
<>();
if
(
group
.
getAttributes
()!=
null
)
{
for
(
Attribute
a
:
group
.
getAttributes
())
{
attributes
.
add
(
a
);
}
}
return
attributes
;
}
}
dariahsp-core/src/main/resources/config.sample.yml
View file @
ada0273c
...
...
@@ -11,17 +11,17 @@ auth:
level
:
100
mappings
:
local
:
[
"
application_admin"
]
saml
2
:
[
"
application_admin"
]
saml
:
[
"
application_admin"
]
-
role
:
CONTRIBUTOR
level
:
50
mappings
:
local
:
[
"
application_contributor"
]
saml
2
:
[
"
application_contributor"
]
saml
:
[
"
application_contributor"
]
-
role
:
USER
level
:
10
mappings
:
local
:
[
"
application_user"
]
saml
2
:
[
"
application_user"
]
saml
:
[
"
application_user"
]
local
:
enabled
:
true
authorizerName
:
local
...
...
@@ -60,14 +60,6 @@ auth:
wantsResponsesSigned
:
false
httpClientTimoutMs
:
2000
attributeConfig
:
-
stage
:
ATTRIBUTES
required
:
true
attributeGroup
:
-
check
:
AND
attributes
:
-
friendlyName
:
mail
name
:
urn:oid:0.9.2342.19200300.100.1.3
nameFormat
:
urn:oasis:names:tc:SAML:2.0:attrname-format:uri
-
stage
:
ATTRIBUTES
required
:
true
attributeGroup
:
...
...
@@ -96,10 +88,11 @@ auth:
-
check
:
OPTIONAL
attributes
:
-
friendlyName
:
mail
mappedAttribute
:
email
name
:
urn:oid:0.9.2342.19200300.100.1.3
nameFormat
:
urn:oasis:names:tc:SAML:2.0:attrname-format:uri
-
friendlyName
:
displayName
mappedAttribute
:
user
name
mappedAttribute
:
display_
name
name
:
urn:oid:2.16.840.1.113730.3.1.241
nameFormat
:
urn:oasis:names:tc:SAML:2.0:attrname-format:uri
-
friendlyName
:
isMemberOf
...
...
dariahsp-sample-boot/src/main/resources/application.yml
View file @
ada0273c
...
...
@@ -23,17 +23,17 @@ auth:
level
:
100
mappings
:
local
:
[
"
application_admin"
]
saml
2
:
[
"
application_
admin"
]
saml
:
[
"
generic-search-
admin
s
"
]
-
role
:
CONTRIBUTOR
level
:
50
mappings
:
local
:
[
"
application_contributor"
]
saml
2
:
[
"
application_
contributor"
]
saml
:
[
"
generic-search-
contributor
s
"
]
-
role
:
USER
level
:
10
mappings
:
local
:
[
"
application_user"
]
saml
2
:
[
"
application_user"
]
saml
:
[
"
application_user"
]
local
:
enabled
:
true
authorizerName
:
local
...
...
@@ -50,7 +50,7 @@ auth:
roles
:
[
"
application_user"
]
saml
:
enabled
:
true
authorizerName
:
SAML2Client
authorizerName
:
saml
keystore
:
path
:
/data/_srv/dariahsp/c105-229.cloud.gwdg.de.jks
pass
:
clariah
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment