Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dariah
dariahsp
Commits
64614fae
Commit
64614fae
authored
Nov 06, 2020
by
Gradl, Tobias
Browse files
10: Work with SAML attributes
Task-Url:
#10
parent
ada0273c
Pipeline
#17771
passed with stage
in 1 minute and 56 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/Constants.java
View file @
64614fae
...
...
@@ -4,5 +4,7 @@ public class Constants {
public
enum
AUTHENTICATION_STAGE
{
AUTHENTICATION
,
ATTRIBUTES
}
public
enum
REQUIRED_ATTRIBUTE_CHECKLOGIC
{
AND
,
OR
,
OPTIONAL
}
public
final
static
String
URN_SAML2_NAMEID_TRANSIENT
=
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
;
}
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/authenticator/SamlProfileCreator.java
View file @
64614fae
...
...
@@ -7,6 +7,9 @@ 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
org.pac4j.saml.credentials.authenticator.SAML2Authenticator
;
import
eu.dariah.de.dariahsp.Constants
;
import
eu.dariah.de.dariahsp.config.Attribute
;
import
eu.dariah.de.dariahsp.config.SecurityConfig
;
import
eu.dariah.de.dariahsp.model.ExtendedUserProfile
;
...
...
@@ -34,19 +37,29 @@ public class SamlProfileCreator extends BaseProfileCreator implements ProfileCre
}
ExtendedUserProfile
profile
=
new
ExtendedUserProfile
(
credentials
.
getUserProfile
());
this
.
assignExternalRoles
(
profile
);
this
.
assignAttributes
(
profile
);
this
.
setIdPersistenceInfo
(
profile
);
this
.
mapAndAssignRoles
(
profile
);
return
Optional
.
ofNullable
(
profile
);
return
Optional
.
ofNullable
(
profile
);
}
private
void
setIdPersistenceInfo
(
ExtendedUserProfile
profile
)
{
boolean
transientId
=
true
;
try
{
if
(
profile
.
containsAttribute
(
SAML2Authenticator
.
SAML_NAME_ID_FORMAT
))
{
transientId
=
profile
.
getAttribute
(
SAML2Authenticator
.
SAML_NAME_ID_FORMAT
,
String
.
class
).
equals
(
Constants
.
URN_SAML2_NAMEID_TRANSIENT
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"Failed to detect and process nameId format"
,
e
);
}
//for ()
}
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
()
);
List
<
String
>
memberOfs
=
(
List
<
String
>)
profile
.
getAttribute
(
EXTERNAL_ROLES_MAPPED_NAME
);
if
(
memberOfs
.
isEmpty
())
{
return
;
}
...
...
@@ -63,30 +76,5 @@ public class SamlProfileCreator extends BaseProfileCreator implements ProfileCre
log
.
warn
(
"Unable to map memberOf attribute to external roles of the profile"
,
e
);
}
}
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/SecurityConfig.java
View file @
64614fae
...
...
@@ -31,6 +31,7 @@ import eu.dariah.de.dariahsp.authenticator.SamlProfileCreator;
import
eu.dariah.de.dariahsp.authenticator.LocalProfileCreator
;
import
eu.dariah.de.dariahsp.config.model.RoleDefinition
;
import
eu.dariah.de.dariahsp.metadata.MetadataHelper
;
import
eu.dariah.de.dariahsp.saml.SAML2RequiredAttributeAuthenticator
;
import
eu.dariah.de.dariahsp.web.AuthInfoHelper
;
import
lombok.Data
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -101,24 +102,22 @@ public class SecurityConfig {
@SuppressWarnings
(
"rawtypes"
)
public
Config
config
()
throws
URISyntaxException
{
List
<
Client
>
clients
=
new
ArrayList
<>();
Optional
<
SAML2Client
>
samlClient
=
getSamlClient
();
Optional
<
FormClient
>
formClient
=
getFormClient
();
SAML2Client
samlClient
=
getSamlClient
();
FormClient
formClient
=
getFormClient
();
if
(
samlClient
.
isPresent
())
{
samlClient
.
get
().
setProfileCreator
(
saml2ProfileCreator
());
clients
.
add
(
samlClient
.
get
());
if
(
samlClient
!=
null
)
{
clients
.
add
(
samlClient
);
}
if
(
formClient
.
isPresent
())
{
formClient
.
get
().
setProfileCreator
(
localProfileCreator
());
clients
.
add
(
formClient
.
get
());
if
(
formClient
!=
null
)
{
clients
.
add
(
formClient
);
}
return
new
Config
(
new
Clients
(
baseUrl
().
getAbsoluteUrl
(
"/callback"
),
clients
));
}
private
Optional
<
SAML2Client
>
getSamlClient
()
throws
URISyntaxException
{
private
SAML2Client
getSamlClient
()
throws
URISyntaxException
{
if
(!
saml
.
isEnabled
())
{
return
Optional
.
empty
()
;
return
null
;
}
final
SAML2Configuration
cfg
=
new
SAML2Configuration
();
...
...
@@ -155,24 +154,27 @@ public class SecurityConfig {
cfg
.
setSignMetadata
(
saml
.
getSp
().
isSignMetadata
());
cfg
.
setSupportedProtocols
(
saml
.
getSp
().
getSupportedProtocols
());
cfg
.
setHttpClient
(
saml
.
getSp
().
getHttpClient
());
cfg
.
setMappedAttributes
(
saml
.
getSp
().
getMappedAttributesNameMap
());
SAML2Client
c
=
new
SAML2Client
(
cfg
);
c
.
setName
(
saml
.
getAuthorizerName
());
return
Optional
.
of
(
c
);
c
.
setProfileCreator
(
saml2ProfileCreator
());
c
.
setAuthenticator
(
new
SAML2RequiredAttributeAuthenticator
(
cfg
.
getAttributeAsId
(),
cfg
.
getMappedAttributes
(),
saml
.
getSp
()));
return
c
;
}
private
Optional
<
FormClient
>
getFormClient
()
throws
URISyntaxException
{
private
FormClient
getFormClient
()
throws
URISyntaxException
{
Optional
<
LocalUsernamePasswordAuthenticator
>
localUsernamePasswordAuthenticator
=
localUsernamePasswordAuthenticator
();
if
(
localUsernamePasswordAuthenticator
.
isPresent
())
{
FormClient
c
=
new
FormClient
(
baseUrl
().
getAbsoluteUrl
(
"/login"
),
localUsernamePasswordAuthenticator
.
get
());
c
.
setName
(
local
.
getAuthorizerName
());
return
Optional
.
of
(
c
);
c
.
setProfileCreator
(
localProfileCreator
());
return
c
;
}
return
Optional
.
empty
()
;
return
null
;
}
private
SamlProfileCreator
saml2ProfileCreator
()
{
SamlProfileCreator
saml2ProfileCreator
=
new
SamlProfileCreator
(
this
,
saml
.
getAuthorizerName
());
saml2ProfileCreator
.
setRoleDefinitions
(
roleDefinitions
);
...
...
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/config/model/SamlSpConfigProperties.java
View file @
64614fae
...
...
@@ -2,7 +2,10 @@ package eu.dariah.de.dariahsp.config.model;
import
java.time.Duration
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
org.apache.http.client.HttpClient
;
...
...
@@ -33,9 +36,6 @@ public class SamlSpConfigProperties {
private
boolean
wantsResponsesSigned
=
true
;
private
List
<
ConditionalAttributeSet
>
attributeConfig
;
private
List
<
Attribute
>
mappedProfileAttributes
=
null
;
// ------------------------------------------
// Custom getters for complex default values
// ------------------------------------------
...
...
@@ -57,19 +57,30 @@ public class SamlSpConfigProperties {
return
httpClient
.
build
();
}
public
List
<
Attribute
>
getMappedProfileAttributes
()
{
if
(
mappedProfileAttributes
!=
null
)
{
return
mappedProfileAttributes
;
public
Attribute
getAttributeByMappedName
(
String
mappedName
)
{
if
(
attributeConfig
!=
null
)
{
return
attributeConfig
.
stream
()
.
map
(
ConditionalAttributeSet:
:
getAttributeGroup
)
.
flatMap
(
Collection:
:
stream
)
.
map
(
ConditionalAttributeGroup:
:
getAttributes
)
.
flatMap
(
Collection:
:
stream
)
.
filter
(
a
->
a
.
getMappedAttribute
().
equals
(
mappedName
))
.
findFirst
()
.
orElse
(
null
);
}
mappedProfileAttributes
=
new
ArrayList
<>();
return
null
;
}
public
Map
<
String
,
String
>
getMappedAttributesNameMap
()
{
Map
<
String
,
String
>
result
=
new
HashMap
<>();
if
(
attributeConfig
!=
null
)
{
for
(
ConditionalAttributeSet
set
:
attributeConfig
)
{
mappedProfileAttributes
.
add
All
(
this
.
getAttributesFromSet
(
set
).
stream
()
result
.
put
All
(
this
.
getAttributesFromSet
(
set
).
stream
()
.
filter
(
a
->
a
.
getMappedAttribute
()!=
null
)
.
collect
(
Collectors
.
to
List
(
)));
.
collect
(
Collectors
.
to
Map
(
Attribute:
:
getName
,
Attribute:
:
getMappedAttribute
)));
}
}
return
mappedProfileAttributes
;
return
result
;
}
private
List
<
Attribute
>
getAttributesFromSet
(
ConditionalAttributeSet
set
)
{
...
...
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/local/LocalAuthenticationProvider.java
deleted
100644 → 0
View file @
ada0273c
package
eu.dariah.de.dariahsp.local
;
/*package eu.dariah.de.dariahsp.sample.local;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import eu.dariah.de.dariahsp.DebugAwareAuthenticationProvider;
import eu.dariah.de.dariahsp.model.User;
import eu.dariah.de.dariahsp.model.UserImpl;
import eu.dariah.de.dariahsp.service.UserService;
public class LocalAuthenticationProvider implements DebugAwareAuthenticationProvider, InitializingBean {
private UserService userService;
private UserDetailsService localUserDb;
private PasswordEncoder encoder;
private String authDebugUser;
private Authentication authDebug;
public UserService getUserService() { return userService; }
public void setUserService(UserService userService) { this.userService = userService; }
public UserDetailsService getLocalUserDb() { return localUserDb; }
public void setLocalUserDb(UserDetailsService localUserDb) { this.localUserDb = localUserDb; }
public PasswordEncoder getEncoder() { return encoder; }
public void setEncoder(PasswordEncoder encoder) { this.encoder = encoder; }
public String isAuthDebugUser() { return authDebugUser; }
public void setAuthDebugUser(String authDebugUser) { this.authDebugUser = authDebugUser; }
@Override
public void afterPropertiesSet() throws Exception {
if (authDebugUser!=null && (System.getProperty("saml")==null || !Boolean.parseBoolean(System.getProperty("saml")))) {
UserDetails user = getLocalUserDb().loadUserByUsername(authDebugUser);
if (user==null) {
user = new UserImpl();
((UserImpl)user).setUsername(authDebugUser);
user = userService.getUserDetails(user);
}
UsernamePasswordAuthenticationToken testAuth = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword().hashCode(), user.getAuthorities());
testAuth.setDetails(user);
userService.saveUser((User)user);
authDebug = testAuth;
}
}
@Override
public Authentication getAuthentication() {
if (authDebug!=null && (System.getProperty("saml")==null || !Boolean.parseBoolean(System.getProperty("saml")))) {
SecurityContextHolder.getContext().setAuthentication(authDebug);
// TODO: allow for a global logout of the test user
// this does not work as intended as session timeouts lead to a logout as well
//this.authDebug = null;
}
return SecurityContextHolder.getContext().getAuthentication();
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
UserDetails user = getLocalUserDb().loadUserByUsername(authentication.getName());
if (encoder.matches(authentication.getCredentials().toString(), user.getPassword())) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword().hashCode(), user.getAuthorities());
User u = userService.getUserDetails(user);
auth.setDetails(u);
userService.saveUser(u);
return auth;
} else {
throw new BadCredentialsException("Wrong password");
}
} catch (Exception e) {
throw new BadCredentialsException("Provided username and/or password wrong.");
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
}
}*/
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/model/ExtendedUserProfile.java
View file @
64614fae
...
...
@@ -14,6 +14,7 @@ import lombok.ToString;
@NoArgsConstructor
@EqualsAndHashCode
(
callSuper
=
true
)
public
class
ExtendedUserProfile
extends
CommonProfile
{
private
boolean
transientId
;
private
Set
<
String
>
externalRoles
;
private
int
level
;
...
...
dariahsp-core/src/main/java/eu/dariah/de/dariahsp/saml/SAML2RequiredAttributeAuthenticator.java
0 → 100644
View file @
64614fae
package
eu.dariah.de.dariahsp.saml
;
import
java.util.Map
;
import
org.pac4j.core.context.WebContext
;
import
org.pac4j.saml.credentials.SAML2Credentials
;
import
org.pac4j.saml.credentials.authenticator.SAML2Authenticator
;
import
eu.dariah.de.dariahsp.config.model.SamlSpConfigProperties
;
import
lombok.extern.slf4j.Slf4j
;
@Slf4j
public
class
SAML2RequiredAttributeAuthenticator
extends
SAML2Authenticator
{
private
final
SamlSpConfigProperties
spConfigProperties
;
public
SAML2RequiredAttributeAuthenticator
(
String
attributeAsId
,
SamlSpConfigProperties
spConfigProperties
)
{
super
(
attributeAsId
);
this
.
spConfigProperties
=
spConfigProperties
;
}
public
SAML2RequiredAttributeAuthenticator
(
final
String
attributeAsId
,
final
Map
<
String
,
String
>
mappedAttributes
,
SamlSpConfigProperties
spConfigProperties
)
{
super
(
attributeAsId
,
mappedAttributes
);
this
.
spConfigProperties
=
spConfigProperties
;
}
@Override
public
void
validate
(
final
SAML2Credentials
credentials
,
final
WebContext
context
)
{
super
.
validate
(
credentials
,
context
);
log
.
debug
(
"Validated profile: {}"
,
credentials
.
getUserProfile
());
// TODO: Perform required attributes checking
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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