/** * Called after successful kerberos authentication * * @param realm realm * @param username username without realm prefix * @return finded or newly created user */ protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) { UserModel user = session.userStorage().getUserByUsername(username, realm); if (user != null) { logger.debugf("Kerberos authenticated user [%s] found in Keycloak storage", username); if (!model.getId().equals(user.getFederationLink())) { logger.warnf( "User with username [%s] already exists, but is not linked to provider [%s]", username, model.getDisplayName()); return null; } else { LDAPObject ldapObject = loadAndValidateUser(realm, user); if (ldapObject != null) { return proxy(realm, user, ldapObject); } else { logger.warnf( "User with username [%s] aready exists and is linked to provider [%s] but is not valid. Stale LDAP_ID on local user is: %s", username, model.getDisplayName(), user.getFirstAttribute(LDAPConstants.LDAP_ID)); logger.warn("Will re-create user"); session.userStorage().removeUser(realm, user); } } } // Creating user to local storage logger.debugf( "Kerberos authenticated user [%s] not in Keycloak storage. Creating him", username); return getUserByUsername(realm, username); }
@Override public CredentialValidationOutput validCredentials( RealmModel realm, UserCredentialModel credential) { if (credential.getType().equals(UserCredentialModel.KERBEROS)) { if (kerberosConfig.isAllowKerberosAuthentication()) { String spnegoToken = credential.getValue(); SPNEGOAuthenticator spnegoAuthenticator = factory.createSPNEGOAuthenticator(spnegoToken, kerberosConfig); spnegoAuthenticator.authenticate(); Map<String, String> state = new HashMap<String, String>(); if (spnegoAuthenticator.isAuthenticated()) { // TODO: This assumes that LDAP "uid" is equal to kerberos principal name. Like uid // "hnelson" and kerberos principal "*****@*****.**". // Check if it's correct or if LDAP attribute for mapping kerberos principal should be // available (For ApacheDS it seems to be attribute "krb5PrincipalName" but on MSAD it's // likely different) String username = spnegoAuthenticator.getAuthenticatedUsername(); UserModel user = findOrCreateAuthenticatedUser(realm, username); if (user == null) { logger.warnf( "Kerberos/SPNEGO authentication succeeded with username [%s], but couldn't find or create user with federation provider [%s]", username, model.getDisplayName()); return CredentialValidationOutput.failed(); } else { String delegationCredential = spnegoAuthenticator.getSerializedDelegationCredential(); if (delegationCredential != null) { state.put(KerberosConstants.GSS_DELEGATION_CREDENTIAL, delegationCredential); } return new CredentialValidationOutput( user, CredentialValidationOutput.Status.AUTHENTICATED, state); } } else { state.put(KerberosConstants.RESPONSE_TOKEN, spnegoAuthenticator.getResponseToken()); return new CredentialValidationOutput( null, CredentialValidationOutput.Status.CONTINUE, state); } } } return CredentialValidationOutput.failed(); }
// 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()); }