use of org.keycloak.dom.saml.v2.protocol.ResponseType in project keycloak by keycloak.
the class SAMLEndpoint method validateInResponseToAttribute.
private boolean validateInResponseToAttribute(ResponseType responseType, String expectedRequestId) {
// If we are not expecting a request ID, don't bother
if (expectedRequestId == null || expectedRequestId.isEmpty())
return true;
// We are expecting a request ID so we are in SP-initiated login, attribute InResponseTo must be present
if (responseType.getInResponseTo() == null) {
logger.error("Response Validation Error: InResponseTo attribute was expected but not present in received response");
return false;
}
// Attribute is present, proceed with validation
// 1) Attribute Response > InResponseTo must not be empty
String responseInResponseToValue = responseType.getInResponseTo();
if (responseInResponseToValue.isEmpty()) {
logger.error("Response Validation Error: InResponseTo attribute was expected but it is empty in received response");
return false;
}
// 2) Attribute Response > InResponseTo must match request ID
if (!responseInResponseToValue.equals(expectedRequestId)) {
logger.error("Response Validation Error: received InResponseTo attribute does not match the expected request ID");
return false;
}
// If present, Assertion > Subject > Confirmation > SubjectConfirmationData > InResponseTo must also be validated
if (responseType.getAssertions().isEmpty())
return true;
SubjectType subjectElement = responseType.getAssertions().get(0).getAssertion().getSubject();
if (subjectElement != null) {
if (subjectElement.getConfirmation() != null && !subjectElement.getConfirmation().isEmpty()) {
SubjectConfirmationType subjectConfirmationElement = subjectElement.getConfirmation().get(0);
if (subjectConfirmationElement != null) {
SubjectConfirmationDataType subjectConfirmationDataElement = subjectConfirmationElement.getSubjectConfirmationData();
if (subjectConfirmationDataElement != null) {
if (subjectConfirmationDataElement.getInResponseTo() != null) {
// 3) Assertion > Subject > Confirmation > SubjectConfirmationData > InResponseTo is empty
String subjectConfirmationDataInResponseToValue = subjectConfirmationDataElement.getInResponseTo();
if (subjectConfirmationDataInResponseToValue.isEmpty()) {
logger.error("Response Validation Error: SubjectConfirmationData InResponseTo attribute was expected but it is empty in received response");
return false;
}
// 4) Assertion > Subject > Confirmation > SubjectConfirmationData > InResponseTo does not match request ID
if (!subjectConfirmationDataInResponseToValue.equals(expectedRequestId)) {
logger.error("Response Validation Error: received SubjectConfirmationData InResponseTo attribute does not match the expected request ID");
return false;
}
}
}
}
}
}
return true;
}
use of org.keycloak.dom.saml.v2.protocol.ResponseType in project keycloak by keycloak.
the class KcSamlBrokerFrontendUrlTest method testFrontendUrlInDestinationExpected.
@Test
public void testFrontendUrlInDestinationExpected() throws URISyntaxException {
SAMLDocumentHolder samlResponse = clientBuilderTrustingAllCertificates().idpInitiatedLogin(new URI(proxy.getUrl() + "/realms/" + bc.consumerRealmName() + "/protocol/saml"), "sales-post").build().login().idp(IDP_SAML_ALIAS).build().processSamlResponse(// AuthnRequest to producer IdP
SamlClient.Binding.POST).targetAttributeSamlRequest().build().login().user(USER_LOGIN, USER_PASSWORD).build().processSamlResponse(SamlClient.Binding.POST).transformObject(saml2Object -> {
assertThat(saml2Object, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
ResponseType response = (ResponseType) saml2Object;
assertThat(response.getDestination(), startsWith(proxy.getUrl()));
return saml2Object;
}).build().updateProfile().username(USER_LOGIN).email(USER_EMAIL).firstName("Firstname").lastName("Lastname").build().followOneRedirect().getSamlResponse(SamlClient.Binding.POST);
assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
}
use of org.keycloak.dom.saml.v2.protocol.ResponseType in project keycloak by keycloak.
the class SAML2Response method createResponseType.
/**
* Create a ResponseType
*
* <b>NOTE:</b>: The PicketLink STS is used to issue/update the assertion
*
* If you want to control over the assertion being issued, then use
* {@link #createResponseType(String, SPInfoHolder, IDPInfoHolder, IssuerInfoHolder, AssertionType)}
*
* @param ID id of the response
* @param sp holder with the information about the Service Provider
* @param idp holder with the information on the Identity Provider
* @param issuerInfo holder with information on the issuer
*
* @return
*
* @throws ConfigurationException
* @throws ProcessingException
*/
public ResponseType createResponseType(String ID, SPInfoHolder sp, IDPInfoHolder idp, IssuerInfoHolder issuerInfo) throws ProcessingException {
String responseDestinationURI = sp.getResponseDestinationURI();
XMLGregorianCalendar issueInstant = XMLTimeUtil.getIssueInstant();
// Create assertion -> subject
SubjectType subjectType = new SubjectType();
// subject -> nameid
NameIDType nameIDType = new NameIDType();
nameIDType.setFormat(idp.getNameIDFormat() == null ? null : URI.create(idp.getNameIDFormat()));
nameIDType.setValue(idp.getNameIDFormatValue());
SubjectType.STSubType subType = new SubjectType.STSubType();
subType.addBaseID(nameIDType);
subjectType.setSubType(subType);
SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType();
subjectConfirmation.setMethod(idp.getSubjectConfirmationMethod());
SubjectConfirmationDataType subjectConfirmationData = new SubjectConfirmationDataType();
subjectConfirmationData.setInResponseTo(sp.getRequestID());
subjectConfirmationData.setRecipient(responseDestinationURI);
// subjectConfirmationData.setNotBefore(issueInstant);
subjectConfirmationData.setNotOnOrAfter(issueInstant);
subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData);
subjectType.addConfirmation(subjectConfirmation);
AssertionType assertionType;
NameIDType issuerID = issuerInfo.getIssuer();
issueInstant = XMLTimeUtil.getIssueInstant();
ConditionsType conditions = null;
List<StatementAbstractType> statements = new LinkedList<>();
// generate an id for the new assertion.
String assertionID = IDGenerator.create("ID_");
assertionType = SAMLAssertionFactory.createAssertion(assertionID, issuerID, issueInstant, conditions, subjectType, statements);
try {
AssertionUtil.createTimedConditions(assertionType, ASSERTION_VALIDITY, CLOCK_SKEW);
} catch (ConfigurationException e) {
throw logger.processingError(e);
} catch (IssueInstantMissingException e) {
throw logger.processingError(e);
}
ResponseType responseType = createResponseType(ID, issuerInfo, assertionType);
// InResponseTo ID
responseType.setInResponseTo(sp.getRequestID());
// Destination
responseType.setDestination(responseDestinationURI);
return responseType;
}
use of org.keycloak.dom.saml.v2.protocol.ResponseType in project keycloak by keycloak.
the class SAML2Response method getSAML2ObjectFromStream.
/**
* Read a {@code SAML2Object} from an input stream
*
* @param is
*
* @return
*
* @throws ParsingException
* @throws ConfigurationException
* @throws ProcessingException
*/
public SAML2Object getSAML2ObjectFromStream(InputStream is) throws ParsingException, ConfigurationException, ProcessingException {
if (is == null)
throw logger.nullArgumentError("InputStream");
Document samlResponseDocument = DocumentUtil.getDocument(is);
if (logger.isTraceEnabled()) {
logger.trace("SAML Response Document: " + DocumentUtil.asString(samlResponseDocument));
}
SAMLParser samlParser = SAMLParser.getInstance();
JAXPValidationUtil.checkSchemaValidation(samlResponseDocument);
SAML2Object responseType = (SAML2Object) samlParser.parse(samlResponseDocument);
samlDocumentHolder = new SAMLDocumentHolder(responseType, samlResponseDocument);
return responseType;
}
use of org.keycloak.dom.saml.v2.protocol.ResponseType in project keycloak by keycloak.
the class SAML2LoginResponseBuilder method buildModel.
public ResponseType buildModel() throws ConfigurationException, ProcessingException {
ResponseType responseType = null;
SAML2Response saml2Response = new SAML2Response();
// Create a response type
String id = IDGenerator.create("ID_");
IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
issuerHolder.setStatusCode(JBossSAMLURIConstants.STATUS_SUCCESS.get());
IDPInfoHolder idp = new IDPInfoHolder();
idp.setNameIDFormatValue(nameId);
idp.setNameIDFormat(nameIdFormat);
SPInfoHolder sp = new SPInfoHolder();
sp.setResponseDestinationURI(destination);
sp.setRequestID(requestID);
sp.setIssuer(requestIssuer);
responseType = saml2Response.createResponseType(id, sp, idp, issuerHolder);
AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
// Add request issuer as the audience restriction
AudienceRestrictionType audience = new AudienceRestrictionType();
audience.addAudience(URI.create(requestIssuer));
assertion.getConditions().addCondition(audience);
// Update Conditions NotOnOrAfter
if (assertionExpiration > 0) {
ConditionsType conditions = assertion.getConditions();
conditions.setNotOnOrAfter(XMLTimeUtil.add(conditions.getNotBefore(), assertionExpiration * 1000L));
}
// Update SubjectConfirmationData NotOnOrAfter
if (subjectExpiration > 0) {
SubjectConfirmationDataType subjectConfirmationData = assertion.getSubject().getConfirmation().get(0).getSubjectConfirmationData();
subjectConfirmationData.setNotOnOrAfter(XMLTimeUtil.add(assertion.getConditions().getNotBefore(), subjectExpiration * 1000L));
}
// Create an AuthnStatementType
if (!disableAuthnStatement) {
String authContextRef = JBossSAMLURIConstants.AC_UNSPECIFIED.get();
if (isNotNull(authMethod))
authContextRef = authMethod;
AuthnStatementType authnStatement = StatementUtil.createAuthnStatement(XMLTimeUtil.getIssueInstant(), authContextRef);
if (sessionExpiration > 0)
authnStatement.setSessionNotOnOrAfter(XMLTimeUtil.add(authnStatement.getAuthnInstant(), sessionExpiration * 1000L));
if (sessionIndex != null)
authnStatement.setSessionIndex(sessionIndex);
else
authnStatement.setSessionIndex(assertion.getID());
assertion.addStatement(authnStatement);
}
if (includeOneTimeUseCondition) {
assertion.getConditions().addCondition(new OneTimeUseType());
}
if (!this.extensions.isEmpty()) {
ExtensionsType extensionsType = new ExtensionsType();
for (NodeGenerator extension : this.extensions) {
extensionsType.addExtension(extension);
}
responseType.setExtensions(extensionsType);
}
return responseType;
}
Aggregations