use of org.keycloak.saml.common.exceptions.ProcessingException in project keycloak by keycloak.
the class SamlService method artifactResolutionService.
/**
* Handles SOAP messages. Chooses the correct response path depending on whether the message is of type ECP or Artifact
* @param inputStream the data of the request.
* @return The response to the SOAP message
*/
@POST
@Path(ARTIFACT_RESOLUTION_SERVICE_PATH)
@NoCache
@Consumes({ "application/soap+xml", MediaType.TEXT_XML })
public Response artifactResolutionService(InputStream inputStream) {
Document soapBodyContents = Soap.extractSoapMessage(inputStream);
ArtifactResolveType artifactResolveType = null;
SAMLDocumentHolder samlDocumentHolder = null;
try {
samlDocumentHolder = SAML2Request.getSAML2ObjectFromDocument(soapBodyContents);
if (samlDocumentHolder.getSamlObject() instanceof ArtifactResolveType) {
logger.debug("Received artifact resolve message");
artifactResolveType = (ArtifactResolveType) samlDocumentHolder.getSamlObject();
}
} catch (Exception e) {
logger.errorf("Artifact resolution endpoint obtained request that contained no " + "ArtifactResolve message: %s", DocumentUtil.asString(soapBodyContents));
return Soap.createFault().reason("").detail("").build();
}
if (artifactResolveType == null) {
logger.errorf("Artifact resolution endpoint obtained request that contained no " + "ArtifactResolve message: %s", DocumentUtil.asString(soapBodyContents));
return Soap.createFault().reason("").detail("").build();
}
try {
return artifactResolve(artifactResolveType, samlDocumentHolder);
} catch (Exception e) {
try {
return emptyArtifactResponseMessage(artifactResolveType, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
} catch (ConfigurationException | ProcessingException configurationException) {
String reason = "An error occurred while trying to return the artifactResponse";
String detail = e.getMessage();
if (detail == null) {
detail = "";
}
logger.errorf("Failure during ArtifactResolve reason: %s, detail: %s", reason, detail);
return Soap.createFault().reason(reason).detail(detail).build();
}
}
}
use of org.keycloak.saml.common.exceptions.ProcessingException in project keycloak by keycloak.
the class SamlService method artifactResolve.
/**
* Takes an artifact resolve message and returns the artifact response, if the artifact is found belonging to a session
* of the issuer.
* @param artifactResolveMessage The artifact resolve message sent by the client
* @param artifactResolveHolder the document containing the artifact resolve message sent by the client
* @return a Response containing the SOAP message with the ArifactResponse
* @throws ParsingException
* @throws ConfigurationException
* @throws ProcessingException
*/
public Response artifactResolve(ArtifactResolveType artifactResolveMessage, SAMLDocumentHolder artifactResolveHolder) throws ParsingException, ConfigurationException, ProcessingException {
logger.debug("Received artifactResolve message for artifact " + artifactResolveMessage.getArtifact() + "\n" + "Message: \n" + DocumentUtil.getDocumentAsString(artifactResolveHolder.getSamlDocument()));
// Artifact from resolve request
String artifact = artifactResolveMessage.getArtifact();
if (artifact == null) {
logger.errorf("Artifact to resolve was null");
return emptyArtifactResponseMessage(artifactResolveMessage, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
}
ArtifactResolver artifactResolver = getArtifactResolver(artifact);
if (artifactResolver == null) {
logger.errorf("Cannot find ArtifactResolver for artifact %s", artifact);
return emptyArtifactResponseMessage(artifactResolveMessage, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
}
// Obtain details of session that issued artifact and check if it corresponds to issuer of Resolve message
SamlArtifactSessionMappingModel sessionMapping = getArtifactSessionMappingStore().get(artifact);
if (sessionMapping == null) {
logger.errorf("No data stored for artifact %s", artifact);
return emptyArtifactResponseMessage(artifactResolveMessage, null);
}
UserSessionModel userSessionModel = session.sessions().getUserSession(realm, sessionMapping.getUserSessionId());
if (userSessionModel == null) {
logger.errorf("UserSession with id: %s, that corresponds to artifact: %s does not exist.", sessionMapping.getUserSessionId(), artifact);
return emptyArtifactResponseMessage(artifactResolveMessage, null);
}
AuthenticatedClientSessionModel clientSessionModel = userSessionModel.getAuthenticatedClientSessions().get(sessionMapping.getClientSessionId());
if (clientSessionModel == null) {
logger.errorf("ClientSession with id: %s, that corresponds to artifact: %s and UserSession: %s does not exist.", sessionMapping.getClientSessionId(), artifact, sessionMapping.getUserSessionId());
return emptyArtifactResponseMessage(artifactResolveMessage, null);
}
ClientModel clientModel = getAndCheckClientModel(sessionMapping.getClientSessionId(), artifactResolveMessage.getIssuer().getValue());
SamlClient samlClient = new SamlClient(clientModel);
// Check signature within ArtifactResolve request if client requires it
if (samlClient.requiresClientSignature()) {
try {
SamlProtocolUtils.verifyDocumentSignature(clientModel, artifactResolveHolder.getSamlDocument());
} catch (VerificationException e) {
SamlService.logger.error("request validation failed", e);
return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
}
}
// Obtain artifactResponse from clientSessionModel
String artifactResponseString;
try {
artifactResponseString = artifactResolver.resolveArtifact(clientSessionModel, artifact);
} catch (ArtifactResolverProcessingException e) {
logger.errorf(e, "Failed to resolve artifact: %s.", artifact);
return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
}
// Artifact is successfully resolved, we can remove session mapping from storage
getArtifactSessionMappingStore().remove(artifact);
Document artifactResponseDocument = null;
ArtifactResponseType artifactResponseType = null;
try {
SAMLDataMarshaller marshaller = new SAMLDataMarshaller();
artifactResponseType = marshaller.deserialize(artifactResponseString, ArtifactResponseType.class);
artifactResponseDocument = SamlProtocolUtils.convert(artifactResponseType);
} catch (ParsingException | ConfigurationException | ProcessingException e) {
logger.errorf(e, "Failed to obtain document from ArtifactResponseString: %s.", artifactResponseString);
return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
}
// If clientSession is in LOGGING_OUT action, now we can move it to LOGGED_OUT
if (CommonClientSessionModel.Action.LOGGING_OUT.name().equals(clientSessionModel.getAction())) {
clientSessionModel.setAction(CommonClientSessionModel.Action.LOGGED_OUT.name());
// If Keycloak sent LogoutResponse we need to also remove UserSession
if (artifactResponseType.getAny() instanceof StatusResponseType && artifactResponseString.contains(JBossSAMLConstants.LOGOUT_RESPONSE.get())) {
if (!UserSessionModel.State.LOGGED_OUT_UNCONFIRMED.equals(userSessionModel.getState())) {
logger.warnf("Keycloak issued LogoutResponse for clientSession %s, however user session %s was not in LOGGED_OUT_UNCONFIRMED state.", clientSessionModel.getId(), userSessionModel.getId());
}
AuthenticationManager.finishUnconfirmedUserSession(session, realm, userSessionModel);
}
}
return artifactResponseMessage(artifactResolveMessage, artifactResponseDocument, clientModel);
}
use of org.keycloak.saml.common.exceptions.ProcessingException in project keycloak by keycloak.
the class EntityDescriptorDescriptionConverter method loadEntityDescriptors.
private static ClientRepresentation loadEntityDescriptors(InputStream is) {
Object metadata;
try {
metadata = SAMLParser.getInstance().parse(is);
} catch (ParsingException e) {
throw new RuntimeException(e);
}
EntitiesDescriptorType entities;
if (EntitiesDescriptorType.class.isInstance(metadata)) {
entities = (EntitiesDescriptorType) metadata;
} else {
entities = new EntitiesDescriptorType();
entities.addEntityDescriptor(metadata);
}
if (entities.getEntityDescriptor().size() != 1) {
throw new RuntimeException("Expected one entity descriptor");
}
EntityDescriptorType entity = (EntityDescriptorType) entities.getEntityDescriptor().get(0);
String entityId = entity.getEntityID();
ClientRepresentation app = new ClientRepresentation();
app.setClientId(entityId);
Map<String, String> attributes = new HashMap<>();
app.setAttributes(attributes);
List<String> redirectUris = new LinkedList<>();
app.setRedirectUris(redirectUris);
app.setFullScopeAllowed(true);
app.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
// default to true
attributes.put(SamlConfigAttributes.SAML_SERVER_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
// default to false
attributes.put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_EXT, SamlProtocol.ATTRIBUTE_FALSE_VALUE);
attributes.put(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM, SignatureAlgorithm.RSA_SHA256.toString());
attributes.put(SamlConfigAttributes.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
SPSSODescriptorType spDescriptorType = getSPDescriptor(entity);
if (spDescriptorType.isWantAssertionsSigned()) {
attributes.put(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
}
String logoutPost = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (logoutPost != null)
attributes.put(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, logoutPost);
String logoutRedirect = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (logoutRedirect != null)
attributes.put(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, logoutRedirect);
String assertionConsumerServicePostBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (assertionConsumerServicePostBinding != null) {
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, assertionConsumerServicePostBinding);
redirectUris.add(assertionConsumerServicePostBinding);
}
String assertionConsumerServiceRedirectBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (assertionConsumerServiceRedirectBinding != null) {
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, assertionConsumerServiceRedirectBinding);
redirectUris.add(assertionConsumerServiceRedirectBinding);
}
String assertionConsumerServiceSoapBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_SOAP_BINDING.get());
if (assertionConsumerServiceSoapBinding != null) {
redirectUris.add(assertionConsumerServiceSoapBinding);
}
String assertionConsumerServicePaosBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_PAOS_BINDING.get());
if (assertionConsumerServicePaosBinding != null) {
redirectUris.add(assertionConsumerServicePaosBinding);
}
String assertionConsumerServiceArtifactBinding = getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_ARTIFACT_BINDING.get());
if (assertionConsumerServiceArtifactBinding != null) {
attributes.put(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_ATTRIBUTE, assertionConsumerServiceArtifactBinding);
redirectUris.add(assertionConsumerServiceArtifactBinding);
}
String artifactResolutionService = getArtifactResolutionService(spDescriptorType);
if (artifactResolutionService != null) {
attributes.put(SamlProtocol.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_ATTRIBUTE, artifactResolutionService);
}
if (spDescriptorType.getNameIDFormat() != null) {
for (String format : spDescriptorType.getNameIDFormat()) {
String attribute = SamlClient.samlNameIDFormatToClientAttribute(format);
if (attribute != null) {
attributes.put(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE, attribute);
break;
}
}
}
if (spDescriptorType.getExtensions() != null && spDescriptorType.getExtensions().getUIInfo() != null) {
if (!spDescriptorType.getExtensions().getUIInfo().getLogo().isEmpty()) {
attributes.put(ClientModel.LOGO_URI, spDescriptorType.getExtensions().getUIInfo().getLogo().get(0).getValue().toString());
}
if (!spDescriptorType.getExtensions().getUIInfo().getPrivacyStatementURL().isEmpty()) {
attributes.put(ClientModel.POLICY_URI, spDescriptorType.getExtensions().getUIInfo().getPrivacyStatementURL().stream().filter(dn -> "en".equals(dn.getLang())).findFirst().orElse(spDescriptorType.getExtensions().getUIInfo().getPrivacyStatementURL().get(0)).getValue().toString());
}
}
app.setProtocolMappers(spDescriptorType.getAttributeConsumingService().stream().flatMap(att -> att.getRequestedAttribute().stream()).map(attr -> {
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
mapper.setName(attr.getName());
mapper.setProtocol("saml");
mapper.setProtocolMapper(UserAttributeStatementMapper.PROVIDER_ID);
Map<String, String> config = new HashMap<>();
config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, attr.getName());
if (attr.getFriendlyName() != null)
config.put(AttributeStatementHelper.FRIENDLY_NAME, attr.getFriendlyName());
if (attr.getNameFormat() != null)
config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, getSAMLNameFormat(attr.getNameFormat()));
mapper.setConfig(config);
return mapper;
}).collect(Collectors.toList()));
for (KeyDescriptorType keyDescriptor : spDescriptorType.getKeyDescriptor()) {
X509Certificate cert = null;
try {
cert = SAMLMetadataUtil.getCertificate(keyDescriptor);
} catch (ConfigurationException e) {
throw new RuntimeException(e);
} catch (ProcessingException e) {
throw new RuntimeException(e);
}
String certPem = KeycloakModelUtils.getPemFromCertificate(cert);
if (keyDescriptor.getUse() == KeyTypes.SIGNING) {
attributes.put(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
attributes.put(SamlConfigAttributes.SAML_SIGNING_CERTIFICATE_ATTRIBUTE, certPem);
} else if (keyDescriptor.getUse() == KeyTypes.ENCRYPTION) {
attributes.put(SamlConfigAttributes.SAML_ENCRYPT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
attributes.put(SamlConfigAttributes.SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE, certPem);
}
}
return app;
}
use of org.keycloak.saml.common.exceptions.ProcessingException in project keycloak by keycloak.
the class KcSamlBrokerTest method emptyAttributeToRoleMapperTest.
@Test
public void emptyAttributeToRoleMapperTest() throws ParsingException, ConfigurationException, ProcessingException {
createRolesForRealm(bc.consumerRealmName());
createRoleMappersForConsumerRealm();
AuthnRequestType loginRep = SamlClient.createLoginRequestDocument(AbstractSamlTest.SAML_CLIENT_ID_SALES_POST + ".dot/ted", getConsumerRoot() + "/sales-post/saml", null);
Document doc = SAML2Request.convert(loginRep);
SAMLDocumentHolder samlResponse = new SamlClientBuilder().authnRequest(getConsumerSamlEndpoint(bc.consumerRealmName()), doc, Binding.POST).build().login().idp(bc.getIDPAlias()).build().processSamlResponse(// AuthnRequest to producer IdP
Binding.POST).targetAttributeSamlRequest().build().login().user(bc.getUserLogin(), bc.getUserPassword()).build().processSamlResponse(// Response from producer IdP
Binding.POST).transformObject(ob -> {
assertThat(ob, org.keycloak.testsuite.util.Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
ResponseType resp = (ResponseType) ob;
Set<StatementAbstractType> statements = resp.getAssertions().get(0).getAssertion().getStatements();
AttributeStatementType attributeType = (AttributeStatementType) statements.stream().filter(statement -> statement instanceof AttributeStatementType).findFirst().orElse(new AttributeStatementType());
AttributeType attr = new AttributeType(EMPTY_ATTRIBUTE_NAME);
attr.addAttributeValue(null);
attributeType.addAttribute(new AttributeStatementType.ASTChoiceType(attr));
resp.getAssertions().get(0).getAssertion().addStatement(attributeType);
return ob;
}).build().updateProfile().firstName("a").lastName("b").email(bc.getUserEmail()).username(bc.getUserLogin()).build().followOneRedirect().getSamlResponse(// Response from consumer IdP
Binding.POST);
Assert.assertThat(samlResponse, Matchers.notNullValue());
Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
Stream<AssertionType> assertionTypeStream = assertionsUnencrypted(samlResponse.getSamlObject());
Stream<AttributeType> attributeStatementTypeStream = attributesUnecrypted(attributeStatements(assertionTypeStream));
Set<String> attributeValues = attributeStatementTypeStream.filter(a -> a.getName().equals(ROLE_ATTRIBUTE_NAME)).flatMap(a -> a.getAttributeValue().stream()).map(Object::toString).collect(Collectors.toSet());
assertThat(attributeValues, hasItems(EMPTY_ATTRIBUTE_ROLE));
}
use of org.keycloak.saml.common.exceptions.ProcessingException in project keycloak by keycloak.
the class BaseSAML2BindingBuilder method generateRedirectUri.
public URI generateRedirectUri(String samlParameterName, String redirectUri, Document document) throws ConfigurationException, ProcessingException, IOException {
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(redirectUri);
int pos = builder.getQuery() == null ? 0 : builder.getQuery().length();
builder.queryParam(samlParameterName, base64Encoded(document));
if (relayState != null) {
builder.queryParam(GeneralConstants.RELAY_STATE, relayState);
}
if (sign) {
builder.queryParam(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, signatureAlgorithm.getXmlSignatureMethod());
URI uri = builder.build();
String rawQuery = uri.getRawQuery();
if (pos > 0) {
// just set in the signature the added SAML parameters
rawQuery = rawQuery.substring(pos + 1);
}
Signature signature = signatureAlgorithm.createSignature();
byte[] sig = new byte[0];
try {
signature.initSign(signingKeyPair.getPrivate());
signature.update(rawQuery.getBytes(GeneralConstants.SAML_CHARSET));
sig = signature.sign();
} catch (InvalidKeyException | SignatureException e) {
throw new ProcessingException(e);
}
String encodedSig = RedirectBindingUtil.base64Encode(sig);
builder.queryParam(GeneralConstants.SAML_SIGNATURE_REQUEST_KEY, encodedSig);
}
return builder.build();
}
Aggregations