Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
*/
package it.infn.mw.iam.authn.saml.profile;

import java.util.Arrays;
import java.util.List;

Check warning on line 18 in iam-login-service/src/main/java/it/infn/mw/iam/authn/saml/profile/IamSSOProfile.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import 'java.util.List'.

See more on https://sonarcloud.io/project/issues?id=indigo-iam_iam&issues=AZ0aV5nucVD-TbPdkCXB&open=AZ0aV5nucVD-TbPdkCXB&pullRequest=1191
import java.util.Set;

Check warning on line 19 in iam-login-service/src/main/java/it/infn/mw/iam/authn/saml/profile/IamSSOProfile.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import 'java.util.Set'.

See more on https://sonarcloud.io/project/issues?id=indigo-iam_iam&issues=AZ0aV5nucVD-TbPdkCXC&open=AZ0aV5nucVD-TbPdkCXC&pullRequest=1191
import java.util.stream.Collectors;

Check warning on line 20 in iam-login-service/src/main/java/it/infn/mw/iam/authn/saml/profile/IamSSOProfile.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import 'java.util.stream.Collectors'.

See more on https://sonarcloud.io/project/issues?id=indigo-iam_iam&issues=AZ0aV5nucVD-TbPdkCXD&open=AZ0aV5nucVD-TbPdkCXD&pullRequest=1191

import javax.xml.namespace.QName;

Expand All @@ -37,8 +36,16 @@
import org.springframework.security.saml.websso.WebSSOProfileImpl;
import org.springframework.security.saml.websso.WebSSOProfileOptions;

import it.infn.mw.iam.config.saml.IamSamlProperties.AuthnContextProperties;

public class IamSSOProfile extends WebSSOProfileImpl {

private final AuthnContextProperties authnContextProperties;

public IamSSOProfile(AuthnContextProperties authnContextProperties) {
this.authnContextProperties = authnContextProperties;
}

private void spidNameIDPolicy(AuthnRequest request) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<NameIDPolicy> builder = (SAMLObjectBuilder<NameIDPolicy>) builderFactory
Expand Down Expand Up @@ -75,34 +82,28 @@
return (SAMLObjectBuilder<T>) builderFactory.getBuilder(elementName);
}

private void addRefedsAuthnContexts(AuthnRequest request) {
RequestedAuthnContext requestedAuthnContext = request.getRequestedAuthnContext();
SAMLObjectBuilder<RequestedAuthnContext> builder =
getBuilder(RequestedAuthnContext.DEFAULT_ELEMENT_NAME);
if (requestedAuthnContext == null) {
requestedAuthnContext = builder.buildObject();
request.setRequestedAuthnContext(requestedAuthnContext);
}
private void configureAuthnContext(AuthnRequest request) {

List<String> requiredClassRefs =
Arrays.asList("https://refeds.org/profile/mfa", "https://refeds.org/profile/sfa",
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified");
if (!authnContextProperties.isEnabled()) {
// Actively clear any AuthnContext the parent class may have already set.
// This ensures NO RequestedAuthnContext is sent letting the IdP decide.
request.setRequestedAuthnContext(null);
return;
}

Set<String> existingRefs = requestedAuthnContext.getAuthnContextClassRefs()
.stream()
.map(AuthnContextClassRef::getAuthnContextClassRef)
.collect(Collectors.toSet());
// Clear and replace with the configured list (admin-defined or defaults)
SAMLObjectBuilder<RequestedAuthnContext> builder =
getBuilder(RequestedAuthnContext.DEFAULT_ELEMENT_NAME);
RequestedAuthnContext requestedAuthnContext = builder.buildObject();
request.setRequestedAuthnContext(requestedAuthnContext);

SAMLObjectBuilder<AuthnContextClassRef> contextRefBuilder =
getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);

for (String ref : requiredClassRefs) {
if (!existingRefs.contains(ref)) {
AuthnContextClassRef classRef = contextRefBuilder.buildObject();
classRef.setAuthnContextClassRef(ref);
requestedAuthnContext.getAuthnContextClassRefs().add(classRef);
}
for (String ref : authnContextProperties.getClassRefs()) {
AuthnContextClassRef classRef = contextRefBuilder.buildObject();
classRef.setAuthnContextClassRef(ref);
requestedAuthnContext.getAuthnContextClassRefs().add(classRef);
}
}

Expand All @@ -114,7 +115,7 @@
AuthnRequest request =
super.getAuthnRequest(context, options, assertionConsumer, bindingService);

addRefedsAuthnContexts(request);
configureAuthnContext(request);

if (options instanceof IamSSOProfileOptions) {
IamSSOProfileOptions ssoOptions = (IamSSOProfileOptions) options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package it.infn.mw.iam.config.saml;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -195,6 +196,34 @@ public String mode() {
}
}

public static class AuthnContextProperties {

private boolean enabled = true;

private List<String> classRefs = Arrays.asList(
"https://refeds.org/profile/mfa",
"https://refeds.org/profile/sfa",
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
);

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public List<String> getClassRefs() {
return classRefs;
}

public void setClassRefs(List<String> classRefs) {
this.classRefs = classRefs;
}
}

private String entityId;

private String keystore;
Expand Down Expand Up @@ -243,6 +272,8 @@ public String mode() {

private long httpClientSocketTimeoutSecs;

private AuthnContextProperties authnContext = new AuthnContextProperties();

public List<IamSamlIdpMetadataProperties> getIdpMetadata() {
return idpMetadata;
}
Expand Down Expand Up @@ -427,4 +458,12 @@ public long getHttpClientSocketTimeoutSecs() {
public void setHttpClientSocketTimeoutSecs(long httpClientSocketTimeoutSecs) {
this.httpClientSocketTimeoutSecs = httpClientSocketTimeoutSecs;
}

public AuthnContextProperties getAuthnContext() {
return authnContext;
}

public void setAuthnContext(AuthnContextProperties authnContext) {
this.authnContext = authnContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ SamlUserIdentifierResolver resolver() {
@Bean
@Profile("saml")
WebSSOProfile webSSOprofile() {
return new IamSSOProfile();
return new IamSSOProfile(samlProperties.getAuthnContext());
}


Expand Down
11 changes: 10 additions & 1 deletion iam-login-service/src/main/resources/application-saml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ saml:
metadata-url: ${IAM_SAML_IDP_METADATA:classpath:/saml/idp-metadata.xml}
require-valid-signature: ${IAM_SAML_METADATA_REQUIRE_VALID_SIGNATURE:false}
require-sirtfi: ${IAM_SAML_METADATA_REQUIRE_SIRTFI:false}
require-rs: ${IAM_SAML_METADATA_REQUIRE_RS:false}
require-rs: ${IAM_SAML_METADATA_REQUIRE_RS:false}

authn-context:
enabled: ${IAM_SAML_AUTHN_CONTEXT_ENABLED:true}
# Set enabled to false to send no AuthnContext at all (IdP determines the appropriate authentication assurance).
# To customise the AuthnContextClassRef values, add a class-refs list
# at the same indentation level as 'enabled' above. For example:
# class-refs:
# - urn:federation:authentication:windows
# - urn:oasis:names:tc:SAML:2.0:ac:classes:Unspecified
Loading