sssd port
This commit is contained in:
parent
0c05dc093f
commit
a3cb3730b4
6 changed files with 41 additions and 98 deletions
|
@ -13,6 +13,12 @@
|
|||
<name>Keycloak SSSD Federation</name>
|
||||
<description/>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.federation.sssd;
|
|||
import org.freedesktop.dbus.Variant;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.credential.CredentialInput;
|
||||
import org.keycloak.credential.CredentialInputValidator;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.federation.sssd.api.Sssd;
|
||||
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
|
||||
|
@ -35,6 +36,9 @@ import org.keycloak.models.UserFederationProviderModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.UserManager;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.user.UserLookupProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -49,16 +53,16 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SSSDFederationProvider implements UserFederationProvider {
|
||||
public class SSSDFederationProvider implements UserStorageProvider, UserLookupProvider, CredentialInputValidator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
|
||||
|
||||
protected static final Set<String> supportedCredentialTypes = new HashSet<>();
|
||||
private final SSSDFederationProviderFactory factory;
|
||||
protected KeycloakSession session;
|
||||
protected UserFederationProviderModel model;
|
||||
protected UserStorageProviderModel model;
|
||||
|
||||
public SSSDFederationProvider(KeycloakSession session, UserFederationProviderModel model, SSSDFederationProviderFactory sssdFederationProviderFactory) {
|
||||
public SSSDFederationProvider(KeycloakSession session, UserStorageProviderModel model, SSSDFederationProviderFactory sssdFederationProviderFactory) {
|
||||
this.session = session;
|
||||
this.model = model;
|
||||
this.factory = sssdFederationProviderFactory;
|
||||
|
@ -70,7 +74,7 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
|
||||
|
||||
@Override
|
||||
public UserModel getUserByUsername(RealmModel realm, String username) {
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
return findOrCreateAuthenticatedUser(realm, username);
|
||||
}
|
||||
|
||||
|
@ -82,22 +86,22 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
* @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
|
||||
*/
|
||||
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
|
||||
UserModel user = session.userStorage().getUserByUsername(username, realm);
|
||||
UserModel user = session.userLocalStorage().getUserByUsername(username, realm);
|
||||
if (user != null) {
|
||||
logger.debug("SSSD authenticated user " + username + " found in Keycloak storage");
|
||||
|
||||
if (!model.getId().equals(user.getFederationLink())) {
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getName() + "]");
|
||||
return null;
|
||||
} else {
|
||||
UserModel proxied = validateAndProxy(realm, user);
|
||||
if (proxied != null) {
|
||||
return proxied;
|
||||
} else {
|
||||
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
|
||||
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getName() +
|
||||
"] but principal is not correct.");
|
||||
logger.warn("Will re-create user");
|
||||
new UserManager(session).removeUser(realm, user, session.userStorage());
|
||||
new UserManager(session).removeUser(realm, user, session.userLocalStorage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +114,7 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
Sssd sssd = new Sssd(username);
|
||||
Map<String, Variant> sssdUser = sssd.getUserAttributes();
|
||||
logger.debugf("Creating SSSD user: %s to local Keycloak storage", username);
|
||||
UserModel user = session.userStorage().addUser(realm, username);
|
||||
UserModel user = session.userLocalStorage().addUser(realm, username);
|
||||
user.setEnabled(true);
|
||||
user.setEmail(Sssd.getRawAttribute(sssdUser.get("mail")));
|
||||
user.setFirstName(Sssd.getRawAttribute(sssdUser.get("givenname")));
|
||||
|
@ -127,18 +131,13 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByEmail(RealmModel realm, String email) {
|
||||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
return Collections.emptyList();
|
||||
public UserModel getUserByEmail(String email, RealmModel realm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,33 +157,11 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(RealmModel realm, UserModel local) {
|
||||
Map<String, Variant> attributes = new Sssd(local.getUsername()).getUserAttributes();
|
||||
return Sssd.getRawAttribute(attributes.get("mail")).equalsIgnoreCase(local.getEmail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedCredentialTypes() {
|
||||
return supportedCredentialTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
||||
if (!(input instanceof UserCredentialModel) || !CredentialModel.PASSWORD.equals(input.getType())) return false;
|
||||
throw new ModelReadOnlyException("Federated storage is not writable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCredentialType(String credentialType) {
|
||||
return CredentialModel.PASSWORD.equals(credentialType);
|
||||
|
@ -204,12 +181,6 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
return (pam.authenticate() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
|
||||
return CredentialValidationOutput.failed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
|
||||
if (isValid(realm, local)) {
|
||||
return new ReadonlySSSDUserModelDelegate(local, this);
|
||||
|
@ -218,21 +189,6 @@ public class SSSDFederationProvider implements UserFederationProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean synchronizeRegistrations() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel register(RealmModel realm, UserModel user) {
|
||||
throw new IllegalStateException("Registration not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
Sssd.disconnect();
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.federation.sssd;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.federation.sssd.api.Sssd;
|
||||
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -28,6 +29,8 @@ import org.keycloak.models.UserFederationProviderFactory;
|
|||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserFederationSyncResult;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
|
@ -37,12 +40,11 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SSSDFederationProviderFactory implements UserFederationProviderFactory, EnvironmentDependentProviderFactory {
|
||||
public class SSSDFederationProviderFactory implements UserStorageProviderFactory<SSSDFederationProvider>, EnvironmentDependentProviderFactory {
|
||||
|
||||
private static final String PROVIDER_NAME = "sssd";
|
||||
private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
|
||||
|
||||
static final Set<String> configOptions = new HashSet<String>();
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
|
@ -50,24 +52,8 @@ public class SSSDFederationProviderFactory implements UserFederationProviderFact
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserFederationProvider getInstance(KeycloakSession session, UserFederationProviderModel model) {
|
||||
return new SSSDFederationProvider(session, model, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* List the configuration options to render and display in the admin console's generic management page for this
|
||||
* plugin
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getConfigurationOptions() {
|
||||
return configOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserFederationProvider create(KeycloakSession session) {
|
||||
return null;
|
||||
public SSSDFederationProvider create(KeycloakSession session, ComponentModel model) {
|
||||
return new SSSDFederationProvider(session, new UserStorageProviderModel(model), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,18 +71,6 @@ public class SSSDFederationProviderFactory implements UserFederationProviderFact
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserFederationSyncResult syncAllUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model) {
|
||||
logger.info("Sync users not supported for this provider");
|
||||
return UserFederationSyncResult.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model, Date lastSync) {
|
||||
logger.info("Sync users not supported for this provider");
|
||||
return UserFederationSyncResult.empty();
|
||||
}
|
||||
|
||||
protected PAMAuthenticator createPAMAuthenticator(String username, String... factors) {
|
||||
return new PAMAuthenticator(username, factors);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.testsuite;
|
||||
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
|
@ -75,6 +76,8 @@ public class Assert extends org.junit.Assert {
|
|||
return ((UserFederationProviderFactoryRepresentation) o1).getId();
|
||||
} else if (o1 instanceof GroupRepresentation) {
|
||||
return ((GroupRepresentation) o1).getName();
|
||||
}else if (o1 instanceof ComponentRepresentation) {
|
||||
return ((ComponentRepresentation) o1).getName();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
|
|
|
@ -5,11 +5,14 @@ import org.junit.Before;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
|
||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
|
@ -61,16 +64,17 @@ public class SSSDTest extends AbstractKeycloakTest {
|
|||
|
||||
@Before
|
||||
public void createUserFederation() {
|
||||
UserFederationProviderRepresentation userFederation = new UserFederationProviderRepresentation();
|
||||
ComponentRepresentation userFederation = new ComponentRepresentation();
|
||||
|
||||
Map<String, String> config = new HashMap<>();
|
||||
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
|
||||
userFederation.setConfig(config);
|
||||
|
||||
userFederation.setDisplayName(DISPLAY_NAME);
|
||||
userFederation.setPriority(0);
|
||||
userFederation.setProviderName(PROVIDER_NAME);
|
||||
userFederation.setName(DISPLAY_NAME);
|
||||
userFederation.getConfig().putSingle("priority", "0");
|
||||
userFederation.setProviderType(UserStorageProvider.class.getName());
|
||||
userFederation.setProviderId(PROVIDER_NAME);
|
||||
|
||||
adminClient.realm(REALM_NAME).userFederation().create(userFederation);
|
||||
adminClient.realm(REALM_NAME).components().add(userFederation);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
|
|
Loading…
Reference in a new issue