public void transformIDToken( KeycloakSession session, IDToken token, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) { Set<ProtocolMapperModel> mappings = new ClientSessionCode(realm, clientSession).getRequestedProtocolMappers(); KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); for (ProtocolMapperModel mapping : mappings) { ProtocolMapper mapper = (ProtocolMapper) sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper()); if (mapper == null || !(mapper instanceof OIDCIDTokenMapper)) continue; token = ((OIDCIDTokenMapper) mapper) .transformIDToken(token, mapping, session, userSession, clientSession); } }
@Override public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) { ClientSessionModel clientSession = accessCode.getClientSession(); ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); String requestID = clientSession.getNote(SAML_REQUEST_ID); String relayState = clientSession.getNote(GeneralConstants.RELAY_STATE); String redirectUri = clientSession.getRedirectUri(); String responseIssuer = getResponseIssuer(realm); String nameIdFormat = getNameIdFormat(samlClient, clientSession); String nameId = getNameId(nameIdFormat, clientSession, userSession); // save NAME_ID and format in clientSession as they may be persistent or transient or email and // not username // we'll need to send this back on a logout clientSession.setNote(SAML_NAME_ID, nameId); clientSession.setNote(SAML_NAME_ID_FORMAT, nameIdFormat); SAML2LoginResponseBuilder builder = new SAML2LoginResponseBuilder(); builder .requestID(requestID) .destination(redirectUri) .issuer(responseIssuer) .assertionExpiration(realm.getAccessCodeLifespan()) .subjectExpiration(realm.getAccessTokenLifespan()) .sessionIndex(clientSession.getId()) .requestIssuer(clientSession.getClient().getClientId()) .nameIdentifier(nameIdFormat, nameId) .authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get()); if (!samlClient.includeAuthnStatement()) { builder.disableAuthnStatement(true); } List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>(); List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>(); ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper = null; Set<ProtocolMapperModel> mappings = accessCode.getRequestedProtocolMappers(); for (ProtocolMapperModel mapping : mappings) { ProtocolMapper mapper = (ProtocolMapper) session .getKeycloakSessionFactory() .getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper()); if (mapper == null) continue; if (mapper instanceof SAMLAttributeStatementMapper) { attributeStatementMappers.add( new ProtocolMapperProcessor<SAMLAttributeStatementMapper>( (SAMLAttributeStatementMapper) mapper, mapping)); } if (mapper instanceof SAMLLoginResponseMapper) { loginResponseMappers.add( new ProtocolMapperProcessor<SAMLLoginResponseMapper>( (SAMLLoginResponseMapper) mapper, mapping)); } if (mapper instanceof SAMLRoleListMapper) { roleListMapper = new ProtocolMapperProcessor<SAMLRoleListMapper>((SAMLRoleListMapper) mapper, mapping); } } Document samlDocument = null; try { ResponseType samlModel = builder.buildModel(); final AttributeStatementType attributeStatement = populateAttributeStatements( attributeStatementMappers, session, userSession, clientSession); populateRoles(roleListMapper, session, userSession, clientSession, attributeStatement); // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute if (attributeStatement.getAttributes().size() > 0) { AssertionType assertion = samlModel.getAssertions().get(0).getAssertion(); assertion.addStatement(attributeStatement); } samlModel = transformLoginResponse( loginResponseMappers, samlModel, session, userSession, clientSession); samlDocument = builder.buildDocument(samlModel); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder(); bindingBuilder.relayState(relayState); KeyManager keyManager = session.keys(); KeyManager.ActiveKey keys = keyManager.getActiveKey(realm); if (samlClient.requiresRealmSignature()) { String canonicalization = samlClient.getCanonicalizationMethod(); if (canonicalization != null) { bindingBuilder.canonicalizationMethod(canonicalization); } bindingBuilder .signatureAlgorithm(samlClient.getSignatureAlgorithm()) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signDocument(); } if (samlClient.requiresAssertionSignature()) { String canonicalization = samlClient.getCanonicalizationMethod(); if (canonicalization != null) { bindingBuilder.canonicalizationMethod(canonicalization); } bindingBuilder .signatureAlgorithm(samlClient.getSignatureAlgorithm()) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signAssertions(); } if (samlClient.requiresEncryption()) { PublicKey publicKey = null; try { publicKey = SamlProtocolUtils.getEncryptionValidationKey(client); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } bindingBuilder.encrypt(publicKey); } try { return buildAuthenticatedResponse(clientSession, redirectUri, samlDocument, bindingBuilder); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } }
// Moved to static method, so it's possible to test this from other places too (for example // export-import tests) public static void assertDataImportedInRealm(KeycloakSession session, RealmModel realm) { Assert.assertTrue(realm.isVerifyEmail()); List<RequiredCredentialModel> creds = realm.getRequiredCredentials(); Assert.assertEquals(1, creds.size()); RequiredCredentialModel cred = creds.get(0); Assert.assertEquals("password", cred.getFormLabel()); Assert.assertEquals(3, realm.getDefaultRoles().size()); Assert.assertNotNull(realm.getRole("foo")); Assert.assertNotNull(realm.getRole("bar")); UserModel user = session.users().getUserByUsername("loginclient", realm); Assert.assertNotNull(user); Assert.assertEquals(0, session.users().getFederatedIdentities(user, realm).size()); List<ClientModel> resources = realm.getClients(); Assert.assertEquals(7, resources.size()); // Test applications imported ClientModel application = realm.getClientByClientId("Application"); ClientModel otherApp = realm.getClientByClientId("OtherApp"); ClientModel accountApp = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); ClientModel nonExisting = realm.getClientByClientId("NonExisting"); Assert.assertNotNull(application); Assert.assertNotNull(otherApp); Assert.assertNull(nonExisting); Map<String, ClientModel> clients = realm.getClientNameMap(); Assert.assertEquals(7, clients.size()); Assert.assertTrue(clients.values().contains(application)); Assert.assertTrue(clients.values().contains(otherApp)); Assert.assertTrue(clients.values().contains(accountApp)); realm.getClients().containsAll(clients.values()); Assert.assertEquals("Applicationn", application.getName()); Assert.assertEquals(50, application.getNodeReRegistrationTimeout()); Map<String, Integer> appRegisteredNodes = application.getRegisteredNodes(); Assert.assertEquals(2, appRegisteredNodes.size()); Assert.assertTrue(10 == appRegisteredNodes.get("node1")); Assert.assertTrue(20 == appRegisteredNodes.get("172.10.15.20")); // test clientAuthenticatorType Assert.assertEquals(application.getClientAuthenticatorType(), "client-secret"); Assert.assertEquals(otherApp.getClientAuthenticatorType(), "client-jwt"); // Test finding applications by ID Assert.assertNull(realm.getClientById("982734")); Assert.assertEquals(application, realm.getClientById(application.getId())); // Test role mappings UserModel admin = session.users().getUserByUsername("admin", realm); // user without creation timestamp in import Assert.assertNull(admin.getCreatedTimestamp()); Set<RoleModel> allRoles = admin.getRoleMappings(); Assert.assertEquals(3, allRoles.size()); Assert.assertTrue(allRoles.contains(realm.getRole("admin"))); Assert.assertTrue(allRoles.contains(application.getRole("app-admin"))); Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-admin"))); Assert.assertTrue(application.getRole("app-admin").isScopeParamRequired()); Assert.assertFalse(otherApp.getRole("otherapp-admin").isScopeParamRequired()); Assert.assertFalse(otherApp.getRole("otherapp-user").isScopeParamRequired()); UserModel wburke = session.users().getUserByUsername("wburke", realm); // user with creation timestamp in import Assert.assertEquals(new Long(123654), wburke.getCreatedTimestamp()); allRoles = wburke.getRoleMappings(); Assert.assertEquals(2, allRoles.size()); Assert.assertFalse(allRoles.contains(realm.getRole("admin"))); Assert.assertTrue(allRoles.contains(application.getRole("app-user"))); Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-user"))); Assert.assertEquals(0, wburke.getRealmRoleMappings().size()); UserModel loginclient = session.users().getUserByUsername("loginclient", realm); // user with creation timestamp as string in import Assert.assertEquals(new Long(123655), loginclient.getCreatedTimestamp()); Set<RoleModel> realmRoles = admin.getRealmRoleMappings(); Assert.assertEquals(1, realmRoles.size()); Assert.assertEquals("admin", realmRoles.iterator().next().getName()); Set<RoleModel> appRoles = admin.getClientRoleMappings(application); Assert.assertEquals(1, appRoles.size()); Assert.assertEquals("app-admin", appRoles.iterator().next().getName()); // Test attributes Map<String, List<String>> attrs = wburke.getAttributes(); Assert.assertEquals(1, attrs.size()); List<String> attrVals = attrs.get("email"); Assert.assertEquals(1, attrVals.size()); Assert.assertEquals("*****@*****.**", attrVals.get(0)); attrs = admin.getAttributes(); Assert.assertEquals(2, attrs.size()); attrVals = attrs.get("key1"); Assert.assertEquals(1, attrVals.size()); Assert.assertEquals("val1", attrVals.get(0)); attrVals = attrs.get("key2"); Assert.assertEquals(2, attrVals.size()); Assert.assertTrue(attrVals.contains("val21") && attrVals.contains("val22")); // Test client ClientModel oauthClient = realm.getClientByClientId("oauthclient"); Assert.assertEquals("clientpassword", oauthClient.getSecret()); Assert.assertEquals(true, oauthClient.isEnabled()); Assert.assertNotNull(oauthClient); // Test scope relationship Set<RoleModel> allScopes = oauthClient.getScopeMappings(); Assert.assertEquals(2, allScopes.size()); Assert.assertTrue(allScopes.contains(realm.getRole("admin"))); Assert.assertTrue(allScopes.contains(application.getRole("app-user"))); Set<RoleModel> realmScopes = oauthClient.getRealmScopeMappings(); Assert.assertTrue(realmScopes.contains(realm.getRole("admin"))); Set<RoleModel> appScopes = application.getClientScopeMappings(oauthClient); Assert.assertTrue(appScopes.contains(application.getRole("app-user"))); // Test social linking UserModel socialUser = session.users().getUserByUsername("mySocialUser", realm); Set<FederatedIdentityModel> socialLinks = session.users().getFederatedIdentities(socialUser, realm); Assert.assertEquals(3, socialLinks.size()); boolean facebookFound = false; boolean googleFound = false; boolean twitterFound = false; for (FederatedIdentityModel federatedIdentityModel : socialLinks) { if ("facebook".equals(federatedIdentityModel.getIdentityProvider())) { facebookFound = true; Assert.assertEquals(federatedIdentityModel.getUserId(), "facebook1"); Assert.assertEquals(federatedIdentityModel.getUserName(), "fbuser1"); } else if ("google".equals(federatedIdentityModel.getIdentityProvider())) { googleFound = true; Assert.assertEquals(federatedIdentityModel.getUserId(), "google1"); Assert.assertEquals(federatedIdentityModel.getUserName(), "*****@*****.**"); } else if ("twitter".equals(federatedIdentityModel.getIdentityProvider())) { twitterFound = true; Assert.assertEquals(federatedIdentityModel.getUserId(), "twitter1"); Assert.assertEquals(federatedIdentityModel.getUserName(), "twuser1"); } } Assert.assertTrue(facebookFound && twitterFound && googleFound); UserModel foundSocialUser = session .users() .getUserByFederatedIdentity( new FederatedIdentityModel("facebook", "facebook1", "fbuser1"), realm); Assert.assertEquals(foundSocialUser.getUsername(), socialUser.getUsername()); Assert.assertNull( session .users() .getUserByFederatedIdentity( new FederatedIdentityModel("facebook", "not-existing", "not-existing"), realm)); FederatedIdentityModel foundSocialLink = session.users().getFederatedIdentity(socialUser, "facebook", realm); Assert.assertEquals("facebook1", foundSocialLink.getUserId()); Assert.assertEquals("fbuser1", foundSocialLink.getUserName()); Assert.assertEquals("facebook", foundSocialLink.getIdentityProvider()); // Test removing social link Assert.assertTrue(session.users().removeFederatedIdentity(realm, socialUser, "facebook")); Assert.assertNull(session.users().getFederatedIdentity(socialUser, "facebook", realm)); Assert.assertFalse(session.users().removeFederatedIdentity(realm, socialUser, "facebook")); session .users() .addFederatedIdentity( realm, socialUser, new FederatedIdentityModel("facebook", "facebook1", "fbuser1")); // Test smtp config Map<String, String> smtpConfig = realm.getSmtpConfig(); Assert.assertTrue(smtpConfig.size() == 3); Assert.assertEquals("*****@*****.**", smtpConfig.get("from")); Assert.assertEquals("localhost", smtpConfig.get("host")); Assert.assertEquals("3025", smtpConfig.get("port")); // Test identity providers List<IdentityProviderModel> identityProviders = realm.getIdentityProviders(); Assert.assertEquals(1, identityProviders.size()); IdentityProviderModel google = identityProviders.get(0); Assert.assertEquals("google1", google.getAlias()); Assert.assertEquals("google", google.getProviderId()); Assert.assertTrue(google.isEnabled()); Assert.assertEquals("googleId", google.getConfig().get("clientId")); Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret")); // Test federation providers List<UserFederationProviderModel> fedProviders = realm.getUserFederationProviders(); Assert.assertTrue(fedProviders.size() == 2); UserFederationProviderModel ldap1 = fedProviders.get(0); Assert.assertEquals("MyLDAPProvider1", ldap1.getDisplayName()); Assert.assertEquals("ldap", ldap1.getProviderName()); Assert.assertEquals(1, ldap1.getPriority()); Assert.assertEquals("ldap://foo", ldap1.getConfig().get(LDAPConstants.CONNECTION_URL)); UserFederationProviderModel ldap2 = fedProviders.get(1); Assert.assertEquals("MyLDAPProvider2", ldap2.getDisplayName()); Assert.assertEquals("ldap://bar", ldap2.getConfig().get(LDAPConstants.CONNECTION_URL)); // Test federation mappers Set<UserFederationMapperModel> fedMappers1 = realm.getUserFederationMappersByFederationProvider(ldap1.getId()); Assert.assertTrue(fedMappers1.size() == 1); UserFederationMapperModel fullNameMapper = fedMappers1.iterator().next(); Assert.assertEquals("FullNameMapper", fullNameMapper.getName()); Assert.assertEquals( FullNameLDAPFederationMapperFactory.PROVIDER_ID, fullNameMapper.getFederationMapperType()); Assert.assertEquals(ldap1.getId(), fullNameMapper.getFederationProviderId()); Assert.assertEquals( "cn", fullNameMapper.getConfig().get(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE)); // All builtin LDAP mappers should be here Set<UserFederationMapperModel> fedMappers2 = realm.getUserFederationMappersByFederationProvider(ldap2.getId()); Assert.assertTrue(fedMappers2.size() > 3); Set<UserFederationMapperModel> allMappers = realm.getUserFederationMappers(); Assert.assertEquals(allMappers.size(), fedMappers1.size() + fedMappers2.size()); // Assert that federation link wasn't created during import UserFederationProviderFactory factory = (UserFederationProviderFactory) session .getKeycloakSessionFactory() .getProviderFactory(UserFederationProvider.class, "dummy"); Assert.assertNull(factory.getInstance(session, null).getUserByUsername(realm, "wburke")); // Test builtin authentication flows AuthenticationFlowModel clientFlow = realm.getClientAuthenticationFlow(); Assert.assertEquals( DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW, clientFlow.getAlias()); Assert.assertNotNull(realm.getAuthenticationFlowById(clientFlow.getId())); Assert.assertTrue(realm.getAuthenticationExecutions(clientFlow.getId()).size() > 0); AuthenticationFlowModel resetFlow = realm.getResetCredentialsFlow(); Assert.assertEquals(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW, resetFlow.getAlias()); Assert.assertNotNull(realm.getAuthenticationFlowById(resetFlow.getId())); Assert.assertTrue(realm.getAuthenticationExecutions(resetFlow.getId()).size() > 0); // Test protocol mappers. Default application has all the builtin protocol mappers. OtherApp // just gss credential Assert.assertNotNull( application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username")); Assert.assertNotNull( application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "email")); Assert.assertNotNull( application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "given name")); Assert.assertNull( application.getProtocolMapperByName( OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME)); Assert.assertEquals(1, otherApp.getProtocolMappers().size()); Assert.assertNull( otherApp.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username")); ProtocolMapperModel gssCredentialMapper = otherApp.getProtocolMapperByName( OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME); Assert.assertEquals( KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME, gssCredentialMapper.getName()); Assert.assertEquals(OIDCLoginProtocol.LOGIN_PROTOCOL, gssCredentialMapper.getProtocol()); Assert.assertEquals(UserSessionNoteMapper.PROVIDER_ID, gssCredentialMapper.getProtocolMapper()); String includeInAccessToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); String includeInIdToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); Assert.assertTrue(includeInAccessToken.equalsIgnoreCase("true")); Assert.assertTrue(includeInIdToken == null || Boolean.parseBoolean(includeInIdToken) == false); // Test user consents admin = session.users().getUserByUsername("admin", realm); Assert.assertEquals(2, admin.getConsents().size()); UserConsentModel appAdminConsent = admin.getConsentByClient(application.getId()); Assert.assertEquals(2, appAdminConsent.getGrantedRoles().size()); Assert.assertTrue( appAdminConsent.getGrantedProtocolMappers() == null || appAdminConsent.getGrantedProtocolMappers().isEmpty()); Assert.assertTrue(appAdminConsent.isRoleGranted(realm.getRole("admin"))); Assert.assertTrue(appAdminConsent.isRoleGranted(application.getRole("app-admin"))); UserConsentModel otherAppAdminConsent = admin.getConsentByClient(otherApp.getId()); Assert.assertEquals(1, otherAppAdminConsent.getGrantedRoles().size()); Assert.assertEquals(1, otherAppAdminConsent.getGrantedProtocolMappers().size()); Assert.assertTrue(otherAppAdminConsent.isRoleGranted(realm.getRole("admin"))); Assert.assertFalse(otherAppAdminConsent.isRoleGranted(application.getRole("app-admin"))); Assert.assertTrue(otherAppAdminConsent.isProtocolMapperGranted(gssCredentialMapper)); // Test service accounts Assert.assertFalse(application.isServiceAccountsEnabled()); Assert.assertTrue(otherApp.isServiceAccountsEnabled()); Assert.assertNull(session.users().getUserByServiceAccountClient(application)); UserModel linked = session.users().getUserByServiceAccountClient(otherApp); Assert.assertNotNull(linked); Assert.assertEquals("my-service-user", linked.getUsername()); }