test user fed registration spi

This commit is contained in:
Bill Burke 2016-07-23 08:55:06 -04:00
parent b6811b96b9
commit 69f051fb0a
10 changed files with 276 additions and 27 deletions

View file

@ -1019,18 +1019,11 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
copy.add(entity);
}
Collections.sort(copy, new Comparator<StorageProviderEntity>() {
@Override
public int compare(StorageProviderEntity o1, StorageProviderEntity o2) {
return o1.getPriority() - o2.getPriority();
}
});
List<StorageProviderModel> result = new LinkedList<>();
for (StorageProviderEntity entity : copy) {
result.add(toModel(entity));
}
Collections.sort(result, StorageProviderModel.comparator);
return Collections.unmodifiableList(result);
}

View file

@ -1311,20 +1311,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
copy.add(entity);
}
Collections.sort(copy, new Comparator<StorageProviderEntity>() {
@Override
public int compare(StorageProviderEntity o1, StorageProviderEntity o2) {
return o1.getPriority() - o2.getPriority();
}
});
List<StorageProviderModel> result = new LinkedList<>();
for (StorageProviderEntity entity : copy) {
result.add(new StorageProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName()
));
}
Collections.sort(result, StorageProviderModel.comparator);
return Collections.unmodifiableList(result);
}

View file

@ -22,7 +22,7 @@ import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserUpdateProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.List;
import java.util.Set;
@ -35,7 +35,7 @@ public interface UserProvider extends Provider,
UserLookupProvider,
UserQueryProvider,
UserCredentialValidatorProvider,
UserUpdateProvider {
UserRegistrationProvider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);

View file

@ -18,6 +18,7 @@
package org.keycloak.storage;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
@ -29,6 +30,13 @@ import java.util.Map;
*/
public class StorageProviderModel implements Serializable {
public static Comparator<StorageProviderModel> comparator = new Comparator<StorageProviderModel>() {
@Override
public int compare(StorageProviderModel o1, StorageProviderModel o2) {
return o1.priority - o2.priority;
}
};
private String id;
private String providerName;
private Map<String, String> config = new HashMap<String, String>();

View file

@ -38,7 +38,7 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserUpdateProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
@ -106,7 +106,7 @@ public class UserStorageManager implements UserProvider {
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserUpdateProvider registry = getFirstStorageProvider(realm, UserUpdateProvider.class);
UserRegistrationProvider registry = getFirstStorageProvider(realm, UserRegistrationProvider.class);
if (registry != null) {
return registry.addUser(realm, id, username, addDefaultRoles, addDefaultRequiredActions);
}
@ -115,7 +115,7 @@ public class UserStorageManager implements UserProvider {
@Override
public UserModel addUser(RealmModel realm, String username) {
UserUpdateProvider registry = getFirstStorageProvider(realm, UserUpdateProvider.class);
UserRegistrationProvider registry = getFirstStorageProvider(realm, UserRegistrationProvider.class);
if (registry != null) {
return registry.addUser(realm, username);
}
@ -139,7 +139,7 @@ public class UserStorageManager implements UserProvider {
if (storageId.getProviderId() == null) {
return localStorage().removeUser(realm, user);
}
UserUpdateProvider registry = (UserUpdateProvider)getStorageProvider(realm, storageId.getProviderId());
UserRegistrationProvider registry = (UserRegistrationProvider)getStorageProvider(realm, storageId.getProviderId());
if (registry == null) {
throw new ModelException("Could not resolve StorageProvider: " + storageId.getProviderId());
}
@ -446,11 +446,11 @@ public class UserStorageManager implements UserProvider {
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
// not federation-aware for now
List<UserUpdateProvider> storageProviders = getStorageProviders(realm, UserUpdateProvider.class);
LinkedList<UserUpdateProvider> providers = new LinkedList<>();
List<UserRegistrationProvider> storageProviders = getStorageProviders(realm, UserRegistrationProvider.class);
LinkedList<UserRegistrationProvider> providers = new LinkedList<>();
providers.add(localStorage());
providers.addAll(storageProviders);
for (UserUpdateProvider provider : providers) {
for (UserRegistrationProvider provider : providers) {
provider.grantToAllUsers(realm, role);
}
}

View file

@ -24,7 +24,7 @@ import org.keycloak.models.UserModel;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserUpdateProvider {
public interface UserRegistrationProvider {
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
UserModel addUser(RealmModel realm, String username);

View file

@ -29,6 +29,7 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.infinispan.UserAdapter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AppPage;
@ -47,12 +48,18 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class UserFederationStorageTest {
public static StorageProviderModel memoryProvider = null;
@ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
StorageProviderModel model = new StorageProviderModel();
model.setDisplayName("memory");
model.setPriority(0);
model.setProviderName(UserMapStorageFactory.PROVIDER_ID);
memoryProvider = appRealm.addStorageProvider(model);
model = new StorageProviderModel();
model.setDisplayName("read-only-user-props");
model.setPriority(1);
model.setProviderName(UserPropertyFileStorageFactory.PROVIDER_ID);
@ -238,4 +245,24 @@ public class UserFederationStorageTest {
keycloakRule.stopSession(session, true);
}
@Test
public void testRegistration() {
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().addUser(realm, "memuser");
user.updateCredential(UserCredentialModel.password("password"));
keycloakRule.stopSession(session, true);
loginSuccessAndLogout("memuser", "password");
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
user = session.users().getUserByUsername("memuser", realm);
Assert.assertEquals(memoryProvider.getId(), StorageId.resolveProviderId(user));
Assert.assertEquals(0, user.getCredentialsDirectly().size());
session.users().removeUser(realm, user);
Assert.assertNull(session.users().getUserByUsername("memuser", realm));
keycloakRule.stopSession(session, true);
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.federation.storage;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserMapStorage implements UserLookupProvider, StorageProvider, UserCredentialValidatorProvider, UserRegistrationProvider {
protected Map<String, String> userPasswords;
protected StorageProviderModel model;
protected KeycloakSession session;
public UserMapStorage(KeycloakSession session, StorageProviderModel model, Map<String, String> userPasswords) {
this.session = session;
this.model = model;
this.userPasswords = userPasswords;
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
StorageId storageId = new StorageId(id);
final String username = storageId.getStorageId();
if (!userPasswords.containsKey(username)) return null;
return createUser(realm, username);
}
private UserModel createUser(RealmModel realm, String username) {
return new AbstractUserAdapterFederatedStorage(session, realm, model) {
@Override
public String getUsername() {
return username;
}
@Override
public void setUsername(String username) {
throw new RuntimeException("Unsupported");
}
@Override
public void updateCredential(UserCredentialModel cred) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
userPasswords.put(username, cred.getValue());
} else {
super.updateCredential(cred);
}
}
};
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
if (!userPasswords.containsKey(username)) return null;
return createUser(realm, username);
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return null;
}
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
userPasswords.put(username, "");
return createUser(realm, username);
}
@Override
public UserModel addUser(RealmModel realm, String username) {
userPasswords.put(username, "");
return createUser(realm, username);
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
return userPasswords.remove(user.getUsername()) != null;
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
}
@Override
public void preRemove(RealmModel realm) {
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel model) {
}
@Override
public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
for (UserCredentialModel cred : input) {
if (!cred.getType().equals(UserCredentialModel.PASSWORD)) return false;
String password = (String)userPasswords.get(user.getUsername());
if (password == null) return false;
if (!password.equals(cred.getValue())) return false;
}
return true;
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,71 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.federation.storage;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderFactory;
import org.keycloak.storage.StorageProviderModel;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserMapStorageFactory implements StorageProviderFactory<UserMapStorage> {
public static final String PROVIDER_ID = "user-password-map";
protected Map<String, String> userPasswords = new Hashtable<>();
@Override
public UserMapStorage getInstance(KeycloakSession session, StorageProviderModel model) {
return new UserMapStorage(session, model, userPasswords);
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public StorageProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
}

View file

@ -1 +1,2 @@
org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
org.keycloak.testsuite.federation.storage.UserMapStorageFactory