Skip to content
This repository was archived by the owner on Sep 28, 2022. It is now read-only.

Commit e058cbb

Browse files
author
Dominik František Bučík
authored
Merge pull request #34 from dBucik/saml
Saml
2 parents cf3c19c + 9aa16ff commit e058cbb

File tree

8 files changed

+89
-38
lines changed

8 files changed

+89
-38
lines changed

perun-oidc-server-webapp/src/main/webapp/WEB-INF/user-context.xml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,14 @@
126126
<prop key="saml.keystore.password">pass</prop>
127127
<prop key="saml.keystore.defaultKey">pass</prop>
128128
<prop key="saml.keystore.defaultKeyPass">pass</prop>
129-
<prop key="saml.idp.defaultIdpEntityId">https://login.cesnet.cz/idp/</prop>
129+
<prop key="saml.idp.defaultIdpEntityId"/>
130130
<prop key="saml.idp.metadataLocation"/> <!-- i.e. /etc/perun/login-cesnet-metadata.xml -->
131131
<prop key="saml.idp.metadataUrl"/> <!-- i.e. https://login.cesnet.cz/proxy/module.php/metadata -->
132-
<prop key="saml.proxy.enabled">true</prop>
133-
<prop key="saml.proxy.spEntityId">https://login.cesnet.cz/proxy/</prop>
132+
<prop key="saml.proxy.spEntityId"/>
133+
<prop key="saml.internalReferrers"/> <!-- comma separated list of URLs (which are matched as prefixes) -->
134134
<prop key="saml.acrs.reserverdPrefixes">urn:cesnet:</prop>
135135
<prop key="saml.acrs.enableComparison">false</prop>
136+
<prop key="saml.user.attrIdentifier">eppn</prop><!-- eppn|epuid|eptid|uid|uniqueIdentifier -->
136137
<!-- STATS JDBC -->
137138
<prop key="stats.jdbc.url">jdbc:mariadb://localhost:3306/STATS</prop>
138139
<prop key="stats.jdbc.user">user</prop>
@@ -197,6 +198,7 @@
197198
<property name="idpMetadataFile" value="${saml.idp.metadataLocation}"/>
198199
<property name="idpMetadataUrl" value="${saml.idp.metadataUrl}"/>
199200
<property name="acrReservedPrefixes" value="#{'${saml.acrs.reserverdPrefixes}'.split('\s*,\s*')}"/>
201+
<property name="userIdentifierAttribute" value="${saml.user.attrIdentifier}"/>
200202
</bean>
201203

202204
<bean id="nonOverwrittenAttributeProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
@@ -485,8 +487,8 @@
485487
<constructor-arg name="pattern" value="/authorize**"/>
486488
<constructor-arg name="oidcIssuer" value="${main.oidc.issuer.url}"/>
487489
<constructor-arg name="idpEntityId" value="${saml.idp.defaultIdpEntityId}"/>
488-
<constructor-arg name="proxyEnabled" value="${saml.proxy.enabled}"/>
489490
<constructor-arg name="proxySpEntityId" value="${saml.proxy.spEntityId}"/>
491+
<constructor-arg name="internalReferrers" value="#{'${saml.internalReferrers}'.split('\s*,\s*')}"/>
490492
<constructor-arg name="contextLogoutHandler" ref="logoutHandler"/>
491493
</bean>
492494
<bean id="samlDiscovery" class="org.springframework.security.saml.SAMLDiscovery">

perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/PerunSamlUserDetailsService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ public class PerunSamlUserDetailsService implements SAMLUserDetailsService {
1515
private static final Logger log = LoggerFactory.getLogger(PerunSamlUserDetailsService.class);
1616

1717
private final PerunAdapter perunAdapter;
18+
private final SamlProperties samlProperties;
1819

1920
@Autowired
20-
public PerunSamlUserDetailsService(PerunAdapter perunAdapter) {
21+
public PerunSamlUserDetailsService(PerunAdapter perunAdapter, SamlProperties samlProperties) {
2122
this.perunAdapter = perunAdapter;
23+
this.samlProperties = samlProperties;
2224
}
2325

2426
@Override
2527
public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
2628
log.debug("Loading user for SAML credential");
27-
PerunPrincipal p = FiltersUtils.getPerunPrincipal(credential);
29+
PerunPrincipal p = FiltersUtils.getPerunPrincipal(credential, samlProperties.getUserIdentifierAttribute());
2830
log.debug("Fetching user from perun ({})", p);
2931
return perunAdapter.getPreauthenticatedUserId(p);
3032
}

perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import static org.springframework.http.HttpHeaders.REFERER;
44

55
import java.io.IOException;
6+
import java.util.ArrayList;
7+
import java.util.Arrays;
8+
import java.util.List;
9+
import java.util.stream.Collectors;
610
import javax.servlet.FilterChain;
711
import javax.servlet.ServletException;
812
import javax.servlet.ServletRequest;
@@ -21,25 +25,34 @@ public class SamlInvalidateSessionFilter extends GenericFilterBean {
2125
private static final Logger log = LoggerFactory.getLogger(SamlInvalidateSessionFilter.class);
2226
private final AntPathRequestMatcher matcher;
2327

24-
private final String idpEntityId;
25-
private final String proxySpEntityId;
26-
private final boolean proxyEnabled;
27-
private final String oidcIssuer;
2828
private final SecurityContextLogoutHandler contextLogoutHandler;
29+
private final List<String> internalReferrers = new ArrayList<>();
2930

3031
public SamlInvalidateSessionFilter(String pattern,
3132
String idpEntityId,
3233
String oidcIssuer,
33-
boolean proxyEnabled,
3434
String proxySpEntityId,
35-
SecurityContextLogoutHandler contextLogoutHandler)
35+
SecurityContextLogoutHandler contextLogoutHandler,
36+
String[] internalReferrers)
3637
{
3738
this.matcher = new AntPathRequestMatcher(pattern);
38-
this.idpEntityId = idpEntityId;
39-
this.oidcIssuer = oidcIssuer;
40-
this.proxyEnabled = proxyEnabled;
41-
this.proxySpEntityId = proxySpEntityId;
39+
if (StringUtils.hasText(idpEntityId)) {
40+
this.internalReferrers.add(idpEntityId);
41+
}
42+
if (StringUtils.hasText(oidcIssuer)) {
43+
this.internalReferrers.add(oidcIssuer);
44+
}
45+
if (StringUtils.hasText(proxySpEntityId)) {
46+
this.internalReferrers.add(proxySpEntityId);
47+
}
4248
this.contextLogoutHandler = contextLogoutHandler;
49+
if (internalReferrers != null && internalReferrers.length > 0) {
50+
List<String> referrers = Arrays.asList(internalReferrers);
51+
referrers = referrers.stream().filter(StringUtils::hasText).collect(Collectors.toList());
52+
if (!referrers.isEmpty()) {
53+
this.internalReferrers.addAll(referrers);
54+
}
55+
}
4356
}
4457

4558
@Override
@@ -59,23 +72,15 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
5972
}
6073

6174
private boolean isInternalReferer(String referer) {
62-
if (!StringUtils.hasText(referer)) {
63-
// no referer, consider as internal
75+
if (!StringUtils.hasText(referer)) { // no referer, consider as internal
6476
return true;
6577
}
66-
67-
boolean isInternal = referer.startsWith(oidcIssuer);
68-
if (!isInternal) {
69-
if (proxyEnabled) {
70-
// check if referer is PROXY (SP part)
71-
isInternal = referer.startsWith(proxySpEntityId);
72-
} else {
73-
// check if referer is IDP
74-
isInternal = referer.startsWith(idpEntityId);
78+
for (String internal : internalReferrers) {
79+
if (referer.startsWith(internal)) {
80+
return true;
7581
}
7682
}
77-
78-
log.debug("Referer {} is internal: {}", referer, isInternal);
79-
return isInternal;
83+
return false;
8084
}
85+
8186
}

perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlProperties.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class SamlProperties implements InitializingBean {
2323
private String idpMetadataFile;
2424
private String idpMetadataUrl;
2525
private String[] acrReservedPrefixes;
26+
private String userIdentifierAttribute;
2627

2728
public String getEntityID() {
2829
return entityID;
@@ -125,4 +126,12 @@ public void setAcrReservedPrefixes(String[] acrReservedPrefixes) {
125126
this.acrReservedPrefixes = nonNull.toArray(new String[0]);
126127
}
127128
}
129+
130+
public String getUserIdentifierAttribute() {
131+
return userIdentifierAttribute;
132+
}
133+
134+
public void setUserIdentifierAttribute(String userIdentifierAttribute) {
135+
this.userIdentifierAttribute = userIdentifierAttribute;
136+
}
128137
}

perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import cz.muni.ics.oidc.BeanUtil;
44
import cz.muni.ics.oidc.models.Facility;
55
import cz.muni.ics.oidc.models.PerunUser;
6+
import cz.muni.ics.oidc.saml.SamlProperties;
67
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
78
import java.io.IOException;
89
import java.util.List;
@@ -47,6 +48,9 @@ public class CallPerunFiltersFilter extends GenericFilterBean {
4748
@Autowired
4849
private PerunAdapter perunAdapter;
4950

51+
@Autowired
52+
private SamlProperties samlProperties;
53+
5054
private PerunFiltersContext perunFiltersContext;
5155

5256
@PostConstruct
@@ -72,7 +76,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
7276
CallPerunFiltersFilter.class.getSimpleName(), client.getClientId(), e);
7377
}
7478
}
75-
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter);
79+
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter, samlProperties.getUserIdentifierAttribute());
7680
FilterParams params = new FilterParams(client, facility, user);
7781
for (PerunRequestFilter filter : filters) {
7882
if (!filter.doFilter(servletRequest, servletResponse, params)) {

perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN;
44
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.SAML_EPUID;
5-
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
65

76
import com.google.common.base.Strings;
87
import cz.muni.ics.oidc.models.Facility;
@@ -31,6 +30,7 @@
3130
import org.springframework.security.saml.SAMLCredential;
3231
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
3332
import org.springframework.security.web.util.matcher.RequestMatcher;
33+
import org.springframework.util.StringUtils;
3434

3535
/**
3636
* Utility class for filters. Contains common methods used by most of filter classes.
@@ -102,12 +102,12 @@ public static ClientDetailsEntity extractClientFromRequest(HttpServletRequest re
102102
* @param perunAdapter Adapter of Perun interface
103103
* @return Found PerunUser
104104
*/
105-
public static PerunUser getPerunUser(HttpServletRequest request, PerunAdapter perunAdapter) {
105+
public static PerunUser getPerunUser(HttpServletRequest request, PerunAdapter perunAdapter, String samlIdAttribute) {
106106
SAMLCredential samlCredential = getSamlCredential(request);
107107
if (samlCredential == null) {
108108
return null;
109109
}
110-
PerunPrincipal principal = getPerunPrincipal(samlCredential);
110+
PerunPrincipal principal = getPerunPrincipal(samlCredential, samlIdAttribute);
111111
log.debug("fetching Perun user with extLogin '{}' and extSourceName '{}'",
112112
principal.getExtLogin(), principal.getExtSourceName());
113113
return perunAdapter.getPreauthenticatedUserId(principal);
@@ -121,8 +121,17 @@ public static SAMLCredential getSamlCredential(HttpServletRequest request) {
121121
return (SAMLCredential) p.getCredentials();
122122
}
123123

124-
public static PerunPrincipal getPerunPrincipal(SAMLCredential credential) {
125-
String extLogin = credential.getAttributeAsString(SAML_EPUID);
124+
public static PerunPrincipal getPerunPrincipal(SAMLCredential credential, String idAttribute) {
125+
if (credential == null) {
126+
throw new IllegalArgumentException("No SAML credential passed");
127+
} else if (!StringUtils.hasText(idAttribute)) {
128+
throw new IllegalArgumentException("No identifier from SAML configured");
129+
}
130+
String identifierAttrOid = PerunFilterConstants.SAML_IDS.getOrDefault(idAttribute, null);
131+
if (identifierAttrOid == null) {
132+
throw new IllegalStateException("SAML credentials has no value for attribute: " + idAttribute);
133+
}
134+
String extLogin = credential.getAttributeAsString(identifierAttrOid);
126135
String extSourceName = credential.getRemoteEntityID();
127136
return new PerunPrincipal(extLogin, extSourceName);
128137
}
@@ -136,7 +145,7 @@ public static PerunPrincipal getPerunPrincipal(SAMLCredential credential) {
136145
public static PerunPrincipal extractPerunPrincipal(HttpServletRequest req, String proxyExtSourceName) {
137146
String extLogin = null;
138147
String remoteUser = req.getRemoteUser();
139-
if (isNotEmpty(remoteUser)) {
148+
if (StringUtils.hasText(remoteUser)) {
140149
extLogin = remoteUser;
141150
} else if (req.getUserPrincipal() != null) {
142151
extLogin = ((User)req.getUserPrincipal()).getUsername();

perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package cz.muni.ics.oidc.server.filters;
22

3+
import java.util.HashMap;
4+
import java.util.Map;
5+
36
/**
47
* Class containing common constants used by Perun request filters.
58
*
@@ -33,8 +36,22 @@ public class PerunFilterConstants {
3336
public static final String EFILTER_PREFIX = "urn:cesnet:proxyidp:efilter:";
3437

3538
public static final String SAML_EPUID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.13";
39+
public static final String SAML_EPPN = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6";
40+
public static final String SAML_EPTID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.10";
41+
public static final String SAML_UID = "urn:oid:0.9.2342.19200300.100.1.1";
42+
public static final String SAML_UNIQUE_IDENTIFIER = "urn:oid:0.9.2342.19200300.100.1.44";
43+
3644
public static final String REFEDS_MFA = "https://refeds.org/profile/mfa";
3745
public static final String PROMPT_LOGIN = "login";
3846
public static final String PROMPT_SELECT_ACCOUNT = "select_account";
3947

48+
public static final Map<String, String> SAML_IDS = new HashMap<>();
49+
static {
50+
SAML_IDS.put("eppn", SAML_EPPN);
51+
SAML_IDS.put("epuid", SAML_EPUID);
52+
SAML_IDS.put("eptid", SAML_EPTID);
53+
SAML_IDS.put("uid", SAML_UID);
54+
SAML_IDS.put("uniqueIdentifier", SAML_UNIQUE_IDENTIFIER);
55+
}
56+
4057
}

perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunForceAupFilter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import cz.muni.ics.oidc.models.PerunAttribute;
1010
import cz.muni.ics.oidc.models.PerunAttributeValue;
1111
import cz.muni.ics.oidc.models.PerunUser;
12+
import cz.muni.ics.oidc.saml.SamlProperties;
1213
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
1314
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
1415
import cz.muni.ics.oidc.server.filters.FilterParams;
@@ -74,13 +75,15 @@ public class PerunForceAupFilter extends PerunRequestFilter {
7475

7576
private final PerunAdapter perunAdapter;
7677
private final PerunOidcConfig perunOidcConfig;
78+
private final SamlProperties samlProperties;
7779
private final String filterName;
7880

7981
public PerunForceAupFilter(PerunRequestFilterParams params) {
8082
super(params);
8183
BeanUtil beanUtil = params.getBeanUtil();
8284
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
8385
this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class);
86+
this.samlProperties = beanUtil.getBean(SamlProperties.class);
8487

8588
this.perunOrgAupsAttrName = params.getProperty(ORG_AUPS_ATTR_NAME);
8689
this.perunUserAupsAttrName = params.getProperty(USER_AUPS_ATTR_NAME);
@@ -102,7 +105,7 @@ protected boolean process(ServletRequest req, ServletResponse res, FilterParams
102105
return true;
103106
}
104107

105-
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter);
108+
PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter, samlProperties.getUserIdentifierAttribute());
106109
if (user == null || user.getId() == null) {
107110
log.debug("{} - skip filter execution: no user provider", filterName);
108111
return true;

0 commit comments

Comments
 (0)