KEYCLOAK-3731 Provide functionality for IdP-initiated SSO for broker
A SAML brokered IdP can send unsolicited login response to the broker. This commit adds a new GET/POST endpoint under [broker SAML endpoint]/clients/{client_id}. Broken will respond to submission to this new endpoint by looking up a SAML client with URL name equal to client_id, and if found, it performs IdP-initiated SSO to that client.
This commit is contained in:
parent
a8de125e26
commit
65b269cd54
6 changed files with 358 additions and 11 deletions
|
@ -66,6 +66,7 @@ import javax.ws.rs.GET;
|
|||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
@ -92,6 +93,7 @@ public class SAMLEndpoint {
|
|||
public static final String SAML_FEDERATED_SUBJECT_NAMEFORMAT = "SAML_FEDERATED_SUBJECT_NAMEFORMAT";
|
||||
public static final String SAML_LOGIN_RESPONSE = "SAML_LOGIN_RESPONSE";
|
||||
public static final String SAML_ASSERTION = "SAML_ASSERTION";
|
||||
public static final String SAML_IDP_INITIATED_CLIENT_ID = "SAML_IDP_INITIATED_CLIENT_ID";
|
||||
public static final String SAML_AUTHN_STATEMENT = "SAML_AUTHN_STATEMENT";
|
||||
protected RealmModel realm;
|
||||
protected EventBuilder event;
|
||||
|
@ -130,7 +132,7 @@ public class SAMLEndpoint {
|
|||
public Response redirectBinding(@QueryParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
|
||||
@QueryParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
|
||||
@QueryParam(GeneralConstants.RELAY_STATE) String relayState) {
|
||||
return new RedirectBinding().execute(samlRequest, samlResponse, relayState);
|
||||
return new RedirectBinding().execute(samlRequest, samlResponse, relayState, null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,7 +143,29 @@ public class SAMLEndpoint {
|
|||
public Response postBinding(@FormParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
|
||||
@FormParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
|
||||
@FormParam(GeneralConstants.RELAY_STATE) String relayState) {
|
||||
return new PostBinding().execute(samlRequest, samlResponse, relayState);
|
||||
return new PostBinding().execute(samlRequest, samlResponse, relayState, null);
|
||||
}
|
||||
|
||||
@Path("clients/{client_id}")
|
||||
@GET
|
||||
public Response redirectBinding(@QueryParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
|
||||
@QueryParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
|
||||
@QueryParam(GeneralConstants.RELAY_STATE) String relayState,
|
||||
@PathParam("client_id") String clientId) {
|
||||
return new RedirectBinding().execute(samlRequest, samlResponse, relayState, clientId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@Path("clients/{client_id}")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response postBinding(@FormParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
|
||||
@FormParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
|
||||
@FormParam(GeneralConstants.RELAY_STATE) String relayState,
|
||||
@PathParam("client_id") String clientId) {
|
||||
return new PostBinding().execute(samlRequest, samlResponse, relayState, clientId);
|
||||
}
|
||||
|
||||
protected abstract class Binding {
|
||||
|
@ -194,12 +218,12 @@ public class SAMLEndpoint {
|
|||
return new HardcodedKeyLocator(keys);
|
||||
}
|
||||
|
||||
public Response execute(String samlRequest, String samlResponse, String relayState) {
|
||||
public Response execute(String samlRequest, String samlResponse, String relayState, String clientId) {
|
||||
event = new EventBuilder(realm, session, clientConnection);
|
||||
Response response = basicChecks(samlRequest, samlResponse);
|
||||
if (response != null) return response;
|
||||
if (samlRequest != null) return handleSamlRequest(samlRequest, relayState);
|
||||
else return handleSamlResponse(samlResponse, relayState);
|
||||
else return handleSamlResponse(samlResponse, relayState, clientId);
|
||||
}
|
||||
|
||||
protected Response handleSamlRequest(String samlRequest, String relayState) {
|
||||
|
@ -304,7 +328,7 @@ public class SAMLEndpoint {
|
|||
private String getEntityId(UriInfo uriInfo, RealmModel realm) {
|
||||
return UriBuilder.fromUri(uriInfo.getBaseUri()).path("realms").path(realm.getName()).build().toString();
|
||||
}
|
||||
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState) {
|
||||
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState, String clientId) {
|
||||
|
||||
try {
|
||||
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
|
||||
|
@ -316,6 +340,9 @@ public class SAMLEndpoint {
|
|||
BrokeredIdentityContext identity = new BrokeredIdentityContext(subjectNameID.getValue());
|
||||
identity.getContextData().put(SAML_LOGIN_RESPONSE, responseType);
|
||||
identity.getContextData().put(SAML_ASSERTION, assertion);
|
||||
if (clientId != null && ! clientId.trim().isEmpty()) {
|
||||
identity.getContextData().put(SAML_IDP_INITIATED_CLIENT_ID, clientId);
|
||||
}
|
||||
|
||||
identity.setUsername(subjectNameID.getValue());
|
||||
|
||||
|
@ -369,7 +396,7 @@ public class SAMLEndpoint {
|
|||
|
||||
|
||||
|
||||
public Response handleSamlResponse(String samlResponse, String relayState) {
|
||||
public Response handleSamlResponse(String samlResponse, String relayState, String clientId) {
|
||||
SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
|
||||
StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject();
|
||||
// validate destination
|
||||
|
@ -390,7 +417,7 @@ public class SAMLEndpoint {
|
|||
}
|
||||
}
|
||||
if (statusResponse instanceof ResponseType) {
|
||||
return handleLoginResponse(samlResponse, holder, (ResponseType)statusResponse, relayState);
|
||||
return handleLoginResponse(samlResponse, holder, (ResponseType)statusResponse, relayState, clientId);
|
||||
|
||||
} else {
|
||||
// todo need to check that it is actually a LogoutResponse
|
||||
|
|
|
@ -611,12 +611,29 @@ public class SamlService extends AuthorizationEndpointBase {
|
|||
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
|
||||
}
|
||||
|
||||
ClientSessionModel clientSession = createClientSessionForIdpInitiatedSso(this.session, this.realm, client, relayState);
|
||||
|
||||
return newBrowserAuthentication(clientSession, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a client session object for SAML IdP-initiated SSO session.
|
||||
* The session takes the parameters from from client definition,
|
||||
* namely binding type and redirect URL.
|
||||
*
|
||||
* @param session KC session
|
||||
* @param realm Realm to create client session in
|
||||
* @param client Client to create client session for
|
||||
* @param relayState Optional relay state - free field as per SAML specification
|
||||
* @return
|
||||
*/
|
||||
public static ClientSessionModel createClientSessionForIdpInitiatedSso(KeycloakSession session, RealmModel realm, ClientModel client, String relayState) {
|
||||
String bindingType = SamlProtocol.SAML_POST_BINDING;
|
||||
if (client.getManagementUrl() == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE) != null) {
|
||||
bindingType = SamlProtocol.SAML_REDIRECT_BINDING;
|
||||
}
|
||||
|
||||
String redirect = null;
|
||||
String redirect;
|
||||
if (bindingType.equals(SamlProtocol.SAML_REDIRECT_BINDING)) {
|
||||
redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE);
|
||||
} else {
|
||||
|
@ -640,8 +657,7 @@ public class SamlService extends AuthorizationEndpointBase {
|
|||
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
|
||||
}
|
||||
|
||||
return newBrowserAuthentication(clientSession, false, false);
|
||||
|
||||
return clientSession;
|
||||
}
|
||||
|
||||
@POST
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.resources;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
||||
|
@ -30,6 +31,7 @@ import org.keycloak.broker.provider.IdentityBrokerException;
|
|||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||
import org.keycloak.broker.provider.IdentityProviderMapper;
|
||||
import org.keycloak.broker.saml.SAMLEndpoint;
|
||||
import org.keycloak.broker.social.SocialIdentityProvider;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.util.ObjectUtil;
|
||||
|
@ -54,8 +56,11 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.FormMessage;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
import org.keycloak.protocol.saml.SamlService;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||
import org.keycloak.services.ErrorPage;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
|
@ -87,6 +92,8 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
|
||||
|
@ -255,7 +262,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
public Response authenticated(BrokeredIdentityContext context) {
|
||||
IdentityProviderModel identityProviderConfig = context.getIdpConfig();
|
||||
|
||||
ParsedCodeContext parsedCode = parseClientSessionCode(context.getCode());
|
||||
final ParsedCodeContext parsedCode;
|
||||
if (context.getContextData().get(SAMLEndpoint.SAML_IDP_INITIATED_CLIENT_ID) != null) {
|
||||
parsedCode = samlIdpInitiatedSSO((String) context.getContextData().get(SAMLEndpoint.SAML_IDP_INITIATED_CLIENT_ID));
|
||||
} else {
|
||||
parsedCode = parseClientSessionCode(context.getCode());
|
||||
}
|
||||
if (parsedCode.response != null) {
|
||||
return parsedCode.response;
|
||||
}
|
||||
|
@ -696,6 +708,53 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
return ParsedCodeContext.response(staleCodeError);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a client whose SAML IDP-initiated SSO URL name is set to the
|
||||
* given {@code clientUrlName}, creates a fresh client session for that
|
||||
* client and returns a {@link ParsedCodeContext} object with that session.
|
||||
* Otherwise returns "client not found" response.
|
||||
*
|
||||
* @param clientUrlName
|
||||
* @return see description
|
||||
*/
|
||||
private ParsedCodeContext samlIdpInitiatedSSO(final String clientUrlName) {
|
||||
event.event(EventType.LOGIN);
|
||||
CacheControlUtil.noBackButtonCacheControlHeader();
|
||||
Optional<ClientModel> oClient = this.realmModel.getClients().stream()
|
||||
.filter(c -> Objects.equals(c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME), clientUrlName))
|
||||
.findFirst();
|
||||
|
||||
if (! oClient.isPresent()) {
|
||||
event.error(Errors.CLIENT_NOT_FOUND);
|
||||
return ParsedCodeContext.response(redirectToErrorPage(Messages.CLIENT_NOT_FOUND));
|
||||
}
|
||||
|
||||
ClientSessionModel clientSession = SamlService.createClientSessionForIdpInitiatedSso(session, realmModel, oClient.get(), null);
|
||||
|
||||
return ParsedCodeContext.clientSessionCode(new ClientSessionCode(session, this.realmModel, clientSession));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the client session is defined for the given code
|
||||
* in the current session and for the current realm.
|
||||
* Does <b>not</b> check the session validity. To obtain client session if
|
||||
* and only if it exists and is valid, use {@link ClientSessionCode#parse}.
|
||||
*
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
protected boolean isClientSessionRegistered(String code) {
|
||||
if (code == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return ClientSessionCode.getClientSession(code, this.session, this.realmModel) != null;
|
||||
} catch (RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Response checkAccountManagementFailedLinking(ClientSessionModel clientSession, String error, Object... parameters) {
|
||||
if (clientSession.getUserSession() != null && clientSession.getClient() != null && clientSession.getClient().getClientId().equals(ACCOUNT_MANAGEMENT_CLIENT_ID)) {
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.common.util.StringPropertyReplacer;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||
import org.keycloak.testsuite.adapter.page.SalesPostServlet;
|
||||
import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
||||
import org.keycloak.testsuite.util.IOUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.junit.Test;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.support.ui.ExpectedCondition;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
|
||||
import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
|
||||
|
||||
private static final String PROVIDER_REALM_USER_NAME = "test";
|
||||
private static final String PROVIDER_REALM_USER_PASSWORD = "test";
|
||||
|
||||
@Page
|
||||
protected LoginPage accountLoginPage;
|
||||
|
||||
@Page
|
||||
protected UpdateAccountInformationPage updateAccountInformationPage;
|
||||
|
||||
protected String getAuthRoot() {
|
||||
return suiteContext.getAuthServerInfo().getContextRoot().toString();
|
||||
}
|
||||
|
||||
private RealmRepresentation loadFromClasspath(String fileName, Properties properties) {
|
||||
InputStream is = KcSamlIdPInitiatedSsoTest.class.getResourceAsStream(fileName);
|
||||
try {
|
||||
String template = StreamUtil.readString(is);
|
||||
String realmString = StringPropertyReplacer.replaceProperties(template, properties);
|
||||
return IOUtil.loadRealm(new ByteArrayInputStream(realmString.getBytes("UTF-8")));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
Properties p = new Properties();
|
||||
p.put("name.realm.provider", REALM_PROV_NAME);
|
||||
p.put("name.realm.consumer", REALM_CONS_NAME);
|
||||
p.put("url.realm.provider", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME);
|
||||
p.put("url.realm.consumer", getAuthRoot() + "/auth/realms/" + REALM_CONS_NAME);
|
||||
|
||||
testRealms.add(loadFromClasspath("kc3731-provider-realm.json", p));
|
||||
testRealms.add(loadFromClasspath("kc3731-broker-realm.json", p));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProviderIdpInitiatedLogin() {
|
||||
driver.navigate().to(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"));
|
||||
|
||||
waitForPage("log in to");
|
||||
|
||||
Assert.assertThat("Driver should be on the provider realm page right now",
|
||||
driver.getCurrentUrl(), containsString("/auth/realms/" + REALM_PROV_NAME + "/"));
|
||||
|
||||
log.debug("Logging in");
|
||||
accountLoginPage.login(PROVIDER_REALM_USER_NAME, PROVIDER_REALM_USER_PASSWORD);
|
||||
|
||||
waitForPage("update account information");
|
||||
|
||||
Assert.assertTrue(updateAccountInformationPage.isCurrent());
|
||||
Assert.assertThat("We must be on consumer realm right now",
|
||||
driver.getCurrentUrl(), containsString("/auth/realms/" + REALM_CONS_NAME + "/"));
|
||||
|
||||
log.debug("Updating info on updateAccount page");
|
||||
updateAccountInformationPage.updateAccountInformation("mytest", "test@localhost", "Firstname", "Lastname");
|
||||
|
||||
UsersResource consumerUsers = adminClient.realm(REALM_CONS_NAME).users();
|
||||
|
||||
int userCount = consumerUsers.count();
|
||||
Assert.assertTrue("There must be at least one user", userCount > 0);
|
||||
|
||||
List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
|
||||
|
||||
boolean isUserFound = users.stream().anyMatch(user -> user.getUsername().equals("mytest") && user.getEmail().equals("test@localhost"));
|
||||
Assert.assertTrue("There must be user " + "mytest" + " in realm " + REALM_CONS_NAME, isUserFound);
|
||||
|
||||
Assert.assertThat(driver.findElement(org.openqa.selenium.By.tagName("form")).getAttribute("action"), containsString("http://localhost:18080/sales-post-enc/"));
|
||||
}
|
||||
|
||||
private String getSamlIdpInitiatedUrl(String realmName, String samlIdpInitiatedSsoUrlName) {
|
||||
return getAuthRoot() + "/auth/realms/" + realmName + "/protocol/saml/clients/" + samlIdpInitiatedSsoUrlName;
|
||||
}
|
||||
|
||||
private void waitForPage(final String title) {
|
||||
WebDriverWait wait = new WebDriverWait(driver, 5);
|
||||
|
||||
ExpectedCondition<Boolean> condition = (WebDriver input) -> input.getTitle().toLowerCase().contains(title);
|
||||
|
||||
wait.until(condition);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"id" : "${name.realm.consumer}",
|
||||
"realm" : "${name.realm.consumer}",
|
||||
"enabled" : true,
|
||||
"sslRequired" : "external",
|
||||
"roles" : {
|
||||
"client" : {
|
||||
"http://localhost:18080/sales-post-enc/" : [ {
|
||||
"name" : "manager"
|
||||
} ]
|
||||
}
|
||||
},
|
||||
"clients" : [ {
|
||||
"clientId": "http://localhost:18080/sales-post-enc/",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"redirectUris": [
|
||||
"http://localhost:18080/sales-post-enc/*"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.authnstatement": "true",
|
||||
"saml.client.signature": "true",
|
||||
"saml.encrypt": "false",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA512",
|
||||
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
|
||||
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||
"saml_idp_initiated_sso_url_name" : "sales"
|
||||
},
|
||||
"baseUrl": "http://localhost:18080/sales-post-enc/",
|
||||
"adminUrl": "http://localhost:18080/sales-post-enc/saml"
|
||||
} ],
|
||||
"identityProviders" : [ {
|
||||
"alias" : "saml-leaf",
|
||||
"providerId" : "saml",
|
||||
"enabled" : true,
|
||||
"updateProfileFirstLoginMode" : "on",
|
||||
"trustEmail" : false,
|
||||
"storeToken" : false,
|
||||
"addReadTokenRoleOnCreate" : false,
|
||||
"authenticateByDefault" : false,
|
||||
"firstBrokerLoginFlowAlias" : "first broker login",
|
||||
"config" : {
|
||||
"nameIDPolicyFormat" : "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
||||
"postBindingAuthnRequest" : "true",
|
||||
"postBindingResponse" : "true",
|
||||
"singleLogoutServiceUrl" : "${url.realm.provider}/protocol/saml",
|
||||
"singleSignOnServiceUrl" : "${url.realm.provider}/protocol/saml",
|
||||
"validateSignature" : "false",
|
||||
"wantAuthnRequestsSigned" : "false"
|
||||
}
|
||||
} ],
|
||||
"identityProviderMappers" : [ {
|
||||
"name" : "manager-role",
|
||||
"identityProviderAlias" : "saml-leaf",
|
||||
"identityProviderMapper" : "saml-role-idp-mapper",
|
||||
"config" : {
|
||||
"attribute.value" : "manager",
|
||||
"role" : "http://localhost:18080/sales-post-enc/.manager",
|
||||
"attribute.name" : "Role"
|
||||
}
|
||||
} ]
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"id" : "${name.realm.provider}",
|
||||
"realm" : "${name.realm.provider}",
|
||||
"enabled" : true,
|
||||
"sslRequired" : "external",
|
||||
"roles" : {
|
||||
"client" : {
|
||||
"${url.realm.consumer}" : [ {
|
||||
"name" : "manager"
|
||||
} ]
|
||||
}
|
||||
},
|
||||
"clients" : [ {
|
||||
"clientId": "${url.realm.consumer}",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"redirectUris": [
|
||||
"${url.realm.consumer}/broker/saml-leaf/endpoint"
|
||||
],
|
||||
"attributes" : {
|
||||
"saml.assertion.signature" : "false",
|
||||
"saml.authnstatement" : "true",
|
||||
"saml.client.signature" : "false",
|
||||
"saml.encrypt" : "false",
|
||||
"saml.force.post.binding" : "true",
|
||||
"saml.server.signature" : "false",
|
||||
"saml_assertion_consumer_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint/clients/sales",
|
||||
"saml_force_name_id_format" : "false",
|
||||
"saml_idp_initiated_sso_url_name" : "samlbroker",
|
||||
"saml_name_id_format" : "persistent",
|
||||
"saml_single_logout_service_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint"
|
||||
}
|
||||
} ],
|
||||
"users" : [ {
|
||||
"username" : "test",
|
||||
"enabled" : true,
|
||||
"email" : "a@localhost",
|
||||
"firstName": "b",
|
||||
"lastName": "c",
|
||||
"credentials" : [ {
|
||||
"type" : "password",
|
||||
"value" : "test"
|
||||
} ],
|
||||
"clientRoles" : {
|
||||
"${url.realm.consumer}" : [ "manager" ]
|
||||
}
|
||||
} ]
|
||||
}
|
Loading…
Reference in a new issue