feat: 🎸 Make SAML identifier attribute configurable
Attribute is configured via property _saml.user.attrIdentifier_ and has to be one of values eppn|epuid|eptid|uid|uniqueIdentifierpull/1580/head
parent
cf3c19c046
commit
39498573c3
|
@ -133,6 +133,7 @@
|
|||
<prop key="saml.proxy.spEntityId">https://login.cesnet.cz/proxy/</prop>
|
||||
<prop key="saml.acrs.reserverdPrefixes">urn:cesnet:</prop>
|
||||
<prop key="saml.acrs.enableComparison">false</prop>
|
||||
<prop key="saml.user.attrIdentifier">eppn</prop><!-- eppn|epuid|eptid|uid|uniqueIdentifier -->
|
||||
<!-- STATS JDBC -->
|
||||
<prop key="stats.jdbc.url">jdbc:mariadb://localhost:3306/STATS</prop>
|
||||
<prop key="stats.jdbc.user">user</prop>
|
||||
|
@ -197,6 +198,7 @@
|
|||
<property name="idpMetadataFile" value="${saml.idp.metadataLocation}"/>
|
||||
<property name="idpMetadataUrl" value="${saml.idp.metadataUrl}"/>
|
||||
<property name="acrReservedPrefixes" value="#{'${saml.acrs.reserverdPrefixes}'.split('\s*,\s*')}"/>
|
||||
<property name="userIdentifierAttribute" value="${saml.user.attrIdentifier}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nonOverwrittenAttributeProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
|
||||
|
|
|
@ -15,16 +15,18 @@ public class PerunSamlUserDetailsService implements SAMLUserDetailsService {
|
|||
private static final Logger log = LoggerFactory.getLogger(PerunSamlUserDetailsService.class);
|
||||
|
||||
private final PerunAdapter perunAdapter;
|
||||
private final SamlProperties samlProperties;
|
||||
|
||||
@Autowired
|
||||
public PerunSamlUserDetailsService(PerunAdapter perunAdapter) {
|
||||
public PerunSamlUserDetailsService(PerunAdapter perunAdapter, SamlProperties samlProperties) {
|
||||
this.perunAdapter = perunAdapter;
|
||||
this.samlProperties = samlProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
|
||||
log.debug("Loading user for SAML credential");
|
||||
PerunPrincipal p = FiltersUtils.getPerunPrincipal(credential);
|
||||
PerunPrincipal p = FiltersUtils.getPerunPrincipal(credential, samlProperties.getUserIdentifierAttribute());
|
||||
log.debug("Fetching user from perun ({})", p);
|
||||
return perunAdapter.getPreauthenticatedUserId(p);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ public class SamlProperties implements InitializingBean {
|
|||
private String idpMetadataFile;
|
||||
private String idpMetadataUrl;
|
||||
private String[] acrReservedPrefixes;
|
||||
private String userIdentifierAttribute;
|
||||
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
|
@ -125,4 +126,12 @@ public class SamlProperties implements InitializingBean {
|
|||
this.acrReservedPrefixes = nonNull.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserIdentifierAttribute() {
|
||||
return userIdentifierAttribute;
|
||||
}
|
||||
|
||||
public void setUserIdentifierAttribute(String userIdentifierAttribute) {
|
||||
this.userIdentifierAttribute = userIdentifierAttribute;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package cz.muni.ics.oidc.server.filters;
|
|||
import cz.muni.ics.oidc.BeanUtil;
|
||||
import cz.muni.ics.oidc.models.Facility;
|
||||
import cz.muni.ics.oidc.models.PerunUser;
|
||||
import cz.muni.ics.oidc.saml.SamlProperties;
|
||||
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -47,6 +48,9 @@ public class CallPerunFiltersFilter extends GenericFilterBean {
|
|||
@Autowired
|
||||
private PerunAdapter perunAdapter;
|
||||
|
||||
@Autowired
|
||||
private SamlProperties samlProperties;
|
||||
|
||||
private PerunFiltersContext perunFiltersContext;
|
||||
|
||||
@PostConstruct
|
||||
|
@ -72,7 +76,7 @@ public class CallPerunFiltersFilter extends GenericFilterBean {
|
|||
CallPerunFiltersFilter.class.getSimpleName(), client.getClientId(), e);
|
||||
}
|
||||
}
|
||||
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter);
|
||||
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter, samlProperties.getUserIdentifierAttribute());
|
||||
FilterParams params = new FilterParams(client, facility, user);
|
||||
for (PerunRequestFilter filter : filters) {
|
||||
if (!filter.doFilter(servletRequest, servletResponse, params)) {
|
||||
|
|
|
@ -2,7 +2,6 @@ package cz.muni.ics.oidc.server.filters;
|
|||
|
||||
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN;
|
||||
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.SAML_EPUID;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import cz.muni.ics.oidc.models.Facility;
|
||||
|
@ -31,6 +30,7 @@ import org.springframework.security.providers.ExpiringUsernameAuthenticationToke
|
|||
import org.springframework.security.saml.SAMLCredential;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility class for filters. Contains common methods used by most of filter classes.
|
||||
|
@ -102,12 +102,12 @@ public class FiltersUtils {
|
|||
* @param perunAdapter Adapter of Perun interface
|
||||
* @return Found PerunUser
|
||||
*/
|
||||
public static PerunUser getPerunUser(HttpServletRequest request, PerunAdapter perunAdapter) {
|
||||
public static PerunUser getPerunUser(HttpServletRequest request, PerunAdapter perunAdapter, String samlIdAttribute) {
|
||||
SAMLCredential samlCredential = getSamlCredential(request);
|
||||
if (samlCredential == null) {
|
||||
return null;
|
||||
}
|
||||
PerunPrincipal principal = getPerunPrincipal(samlCredential);
|
||||
PerunPrincipal principal = getPerunPrincipal(samlCredential, samlIdAttribute);
|
||||
log.debug("fetching Perun user with extLogin '{}' and extSourceName '{}'",
|
||||
principal.getExtLogin(), principal.getExtSourceName());
|
||||
return perunAdapter.getPreauthenticatedUserId(principal);
|
||||
|
@ -121,8 +121,17 @@ public class FiltersUtils {
|
|||
return (SAMLCredential) p.getCredentials();
|
||||
}
|
||||
|
||||
public static PerunPrincipal getPerunPrincipal(SAMLCredential credential) {
|
||||
String extLogin = credential.getAttributeAsString(SAML_EPUID);
|
||||
public static PerunPrincipal getPerunPrincipal(SAMLCredential credential, String idAttribute) {
|
||||
if (credential == null) {
|
||||
throw new IllegalArgumentException("No SAML credential passed");
|
||||
} else if (!StringUtils.hasText(idAttribute)) {
|
||||
throw new IllegalArgumentException("No identifier from SAML configured");
|
||||
}
|
||||
String identifierAttrOid = PerunFilterConstants.SAML_IDS.getOrDefault(idAttribute, null);
|
||||
if (identifierAttrOid == null) {
|
||||
throw new IllegalStateException("SAML credentials has no value for attribute: " + idAttribute);
|
||||
}
|
||||
String extLogin = credential.getAttributeAsString(identifierAttrOid);
|
||||
String extSourceName = credential.getRemoteEntityID();
|
||||
return new PerunPrincipal(extLogin, extSourceName);
|
||||
}
|
||||
|
@ -136,7 +145,7 @@ public class FiltersUtils {
|
|||
public static PerunPrincipal extractPerunPrincipal(HttpServletRequest req, String proxyExtSourceName) {
|
||||
String extLogin = null;
|
||||
String remoteUser = req.getRemoteUser();
|
||||
if (isNotEmpty(remoteUser)) {
|
||||
if (StringUtils.hasText(remoteUser)) {
|
||||
extLogin = remoteUser;
|
||||
} else if (req.getUserPrincipal() != null) {
|
||||
extLogin = ((User)req.getUserPrincipal()).getUsername();
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package cz.muni.ics.oidc.server.filters;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class containing common constants used by Perun request filters.
|
||||
*
|
||||
|
@ -33,8 +36,22 @@ public class PerunFilterConstants {
|
|||
public static final String EFILTER_PREFIX = "urn:cesnet:proxyidp:efilter:";
|
||||
|
||||
public static final String SAML_EPUID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.13";
|
||||
public static final String SAML_EPPN = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6";
|
||||
public static final String SAML_EPTID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.10";
|
||||
public static final String SAML_UID = "urn:oid:0.9.2342.19200300.100.1.1";
|
||||
public static final String SAML_UNIQUE_IDENTIFIER = "urn:oid:0.9.2342.19200300.100.1.44";
|
||||
|
||||
public static final String REFEDS_MFA = "https://refeds.org/profile/mfa";
|
||||
public static final String PROMPT_LOGIN = "login";
|
||||
public static final String PROMPT_SELECT_ACCOUNT = "select_account";
|
||||
|
||||
public static final Map<String, String> SAML_IDS = new HashMap<>();
|
||||
static {
|
||||
SAML_IDS.put("eppn", SAML_EPPN);
|
||||
SAML_IDS.put("epuid", SAML_EPUID);
|
||||
SAML_IDS.put("eptid", SAML_EPTID);
|
||||
SAML_IDS.put("uid", SAML_UID);
|
||||
SAML_IDS.put("uniqueIdentifier", SAML_UNIQUE_IDENTIFIER);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import cz.muni.ics.oidc.models.Facility;
|
|||
import cz.muni.ics.oidc.models.PerunAttribute;
|
||||
import cz.muni.ics.oidc.models.PerunAttributeValue;
|
||||
import cz.muni.ics.oidc.models.PerunUser;
|
||||
import cz.muni.ics.oidc.saml.SamlProperties;
|
||||
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
|
||||
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
|
||||
import cz.muni.ics.oidc.server.filters.FilterParams;
|
||||
|
@ -74,6 +75,7 @@ public class PerunForceAupFilter extends PerunRequestFilter {
|
|||
|
||||
private final PerunAdapter perunAdapter;
|
||||
private final PerunOidcConfig perunOidcConfig;
|
||||
private final SamlProperties samlProperties;
|
||||
private final String filterName;
|
||||
|
||||
public PerunForceAupFilter(PerunRequestFilterParams params) {
|
||||
|
@ -81,6 +83,7 @@ public class PerunForceAupFilter extends PerunRequestFilter {
|
|||
BeanUtil beanUtil = params.getBeanUtil();
|
||||
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
|
||||
this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class);
|
||||
this.samlProperties = beanUtil.getBean(SamlProperties.class);
|
||||
|
||||
this.perunOrgAupsAttrName = params.getProperty(ORG_AUPS_ATTR_NAME);
|
||||
this.perunUserAupsAttrName = params.getProperty(USER_AUPS_ATTR_NAME);
|
||||
|
@ -102,7 +105,7 @@ public class PerunForceAupFilter extends PerunRequestFilter {
|
|||
return true;
|
||||
}
|
||||
|
||||
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter);
|
||||
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter, samlProperties.getUserIdentifierAttribute());
|
||||
if (user == null || user.getId() == null) {
|
||||
log.debug("{} - skip filter execution: no user provider", filterName);
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue