Skip to content

Commit

Permalink
SAML Assertion validation should propagate errors: #7375 and #7375
Browse files Browse the repository at this point in the history
  • Loading branch information
fhanik committed Sep 24, 2019
1 parent 20033ff commit d472e99
Show file tree
Hide file tree
Showing 8 changed files with 1,190 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ dependencies {
compile("org.opensaml:opensaml-saml-impl")

provided 'javax.servlet:javax.servlet-api'

testCompile powerMock2Dependencies
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.security.saml2.provider.service.authentication;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.Assert;

/**
* This exception is thrown for all SAML 2.0 related {@link Authentication} errors.
*
* <p>
* There are a number of scenarios where an error may occur, for example:
* <ul>
* <li>The response or assertion request is missing or malformed</li>
* <li>Missing or invalid subject</li>
* <li>Missing or invalid signatures</li>
* <li>The time period validation for the assertion fails</li>
* <li>One of the assertion conditions was not met</li>
* <li>Decryption failed</li>
* <li>Unable to locate a subject identifier, commonly known as username</li>
* </ul>
*
* @since 5.2
*/
public class Saml2AuthenticationException extends AuthenticationException {
private Saml2Error error;

/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
*
* @param error the {@link Saml2Error SAML 2.0 Error}
*/
public Saml2AuthenticationException(Saml2Error error) {
this(error, error.getDescription());
}

/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
*
* @param error the {@link Saml2Error SAML 2.0 Error}
* @param cause the root cause
*/
public Saml2AuthenticationException(Saml2Error error, Throwable cause) {
this(error, cause.getMessage(), cause);
}

/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
*
* @param error the {@link Saml2Error SAML 2.0 Error}
* @param message the detail message
*/
public Saml2AuthenticationException(Saml2Error error, String message) {
super(message);
this.setError(error);
}

/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
*
* @param error the {@link Saml2Error SAML 2.0 Error}
* @param message the detail message
* @param cause the root cause
*/
public Saml2AuthenticationException(Saml2Error error, String message, Throwable cause) {
super(message, cause);
this.setError(error);
}

/**
* Returns the {@link Saml2Error SAML 2.0 Error}.
*
* @return the {@link Saml2Error}
*/
public Saml2Error getError() {
return this.error;
}

private void setError(Saml2Error error) {
Assert.notNull(error, "error cannot be null");
this.error = error;
}

@Override
public String toString() {
final StringBuffer sb = new StringBuffer("Saml2AuthenticationException{");
sb.append("error=").append(error);
sb.append('}');
return sb.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.security.saml2.provider.service.authentication;

import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.Assert;

import java.io.Serializable;

/**
* A representation of an SAML 2.0 Error.
*
* <p>
* At a minimum, an error response will contain an error code.
* The commonly used error code are defined in this class
* or a new codes can be defined in the future as arbitrary strings.
* </p>
* @since 5.2
*/
public class Saml2Error implements Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

private final String errorCode;
private final String description;

/**
* Constructs a {@code Saml2Error} using the provided parameters.
*
* @param errorCode the error code
* @param description the error description
*/
public Saml2Error(String errorCode, String description) {
Assert.hasText(errorCode, "errorCode cannot be empty");
this.errorCode = errorCode;
this.description = description;
}

/**
* Returns the error code.
*
* @return the error code
*/
public final String getErrorCode() {
return this.errorCode;
}

/**
* Returns the error description.
*
* @return the error description
*/
public final String getDescription() {
return this.description;
}

@Override
public String toString() {
return "[" + this.getErrorCode() + "] " +
(this.getDescription() != null ? this.getDescription() : "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.security.saml2.provider.service.authentication;

/**
* A list of SAML known 2 error codes used during SAML authentication.
*
* @since 5.2
*/
public interface Saml2ErrorCodes {
/**
* SAML Data does not represent a SAML 2 Response object.
* A valid XML object was received, but that object was not a
* SAML 2 Response object of type {@code ResponseType} per specification
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=46
*/
String UNKNOWN_RESPONSE_CLASS = "unknown_response_class";
/**
* The response data is malformed or incomplete.
* An invalid XML object was received, and XML unmarshalling failed.
*/
String MALFORMED_RESPONSE_DATA = "malformed_response_data";
/**
* Response destination does not match the request URL.
* A SAML 2 response object was received at a URL that
* did not match the URL stored in the {code Destination} attribute
* in the Response object.
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38
*/
String INVALID_DESTINATION = "invalid_destination";
/**
* The assertion was not valid.
* The assertion used for authentication failed validation.
* Details around the failure will be present in the error description.
*/
String INVALID_ASSERTION = "invalid_assertion";
/**
* The signature of response or assertion was invalid.
* Either the response or the assertion was missing a signature
* or the signature could not be verified using the system's
* configured credentials. Most commonly the IDP's
* X509 certificate.
*/
String INVALID_SIGNATURE = "invalid_signature";
/**
* The assertion did not contain a subject element.
* The subject element, type SubjectType, contains
* a {@code NameID} or an {@code EncryptedID} that is used
* to assign the authenticated principal an identifier,
* typically a username.
*
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
*/
String SUBJECT_NOT_FOUND = "subject_not_found";
/**
* The subject did not contain a user identifier
* The assertion contained a subject element, but the subject
* element did not have a {@code NameID} or {@code EncryptedID}
* element
*
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
*/
String USERNAME_NOT_FOUND = "username_not_found";
/**
* The system failed to decrypt an assertion or a name identifier.
* This error code will be thrown if the decryption of either a
* {@code EncryptedAssertion} or {@code EncryptedID} fails.
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=17
*/
String DECRYPTION_ERROR = "decryption_error";
/**
* An Issuer element contained a value that didn't
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=15
*/
String INVALID_ISSUER = "invalid_issuer";
/**
* An error happened during validation.
* Used when internal, non classified, errors are caught during the
* authentication process.
*/
String INTERNAL_VALIDATION_ERROR = "internal_validation_error";
}
Loading

0 comments on commit d472e99

Please sign in to comment.