component model

This commit is contained in:
Bill Burke 2016-08-01 11:18:58 -04:00 committed by mposolda
parent 3b3368eead
commit 09693eb108
92 changed files with 2097 additions and 1044 deletions

View file

@ -0,0 +1,101 @@
/*
* 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.representations.idm;
import org.keycloak.common.util.MultivaluedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ComponentRepresentation {
private String id;
private String name;
private String providerId;
private String providerType;
private String parentId;
private MultivaluedHashMap<String, String> config;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getProviderType() {
return providerType;
}
public void setProviderType(String providerType) {
this.providerType = providerType;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public MultivaluedHashMap<String, String> getConfig() {
return config;
}
public void setConfig(MultivaluedHashMap<String, String> config) {
this.config = config;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ComponentRepresentation that = (ComponentRepresentation) o;
if (!id.equals(that.id)) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -0,0 +1,57 @@
/*
* 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.representations.idm;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ComponentTypeRepresentation {
protected String id;
protected String helpText;
protected List<ConfigPropertyRepresentation> properties;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getHelpText() {
return helpText;
}
public void setHelpText(String helpText) {
this.helpText = helpText;
}
public List<ConfigPropertyRepresentation> getProperties() {
return properties;
}
public void setProperties(List<ConfigPropertyRepresentation> properties) {
this.properties = properties;
}
}

View file

@ -15,20 +15,36 @@
* limitations under the License.
*/
package org.keycloak.models.entities;
package org.keycloak.representations.idm;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class StorageProviderEntity extends AbstractIdentifiableEntity {
protected String providerName;
protected Map<String, String> config;
protected int priority;
protected String displayName;
public class StorageProviderRepresentation {
private String id;
private String displayName;
private String providerName;
private Map<String, String> config;
private int priority;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getProviderName() {
return providerName;
@ -38,6 +54,7 @@ public class StorageProviderEntity extends AbstractIdentifiableEntity {
this.providerName = providerName;
}
public Map<String, String> getConfig() {
return config;
}
@ -54,12 +71,20 @@ public class StorageProviderEntity extends AbstractIdentifiableEntity {
this.priority = priority;
}
public String getDisplayName() {
return displayName;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StorageProviderRepresentation that = (StorageProviderRepresentation) o;
if (!id.equals(that.id)) return false;
return true;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -17,6 +17,7 @@
package org.keycloak.representations.info;
import org.keycloak.representations.idm.ComponentTypeRepresentation;
import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
@ -43,6 +44,7 @@ public class ServerInfoRepresentation {
private Map<String, List<ProtocolMapperTypeRepresentation>> protocolMapperTypes;
private Map<String, List<ProtocolMapperRepresentation>> builtinProtocolMappers;
private Map<String, List<ClientInstallationRepresentation>> clientInstallations;
private Map<String, List<ComponentTypeRepresentation>> componentTypes;
private List<PasswordPolicyTypeRepresentation> passwordPolicies;
@ -144,4 +146,11 @@ public class ServerInfoRepresentation {
this.passwordPolicies = passwordPolicies;
}
public Map<String, List<ComponentTypeRepresentation>> getComponentTypes() {
return componentTypes;
}
public void setComponentTypes(Map<String, List<ComponentTypeRepresentation>> componentTypes) {
this.componentTypes = componentTypes;
}
}

View file

@ -37,5 +37,6 @@
<module>authenticator</module>
<module>rest</module>
<module>domain-extension</module>
<module>user-storage-jpa</module>
</modules>
</project>

View file

@ -0,0 +1,118 @@
/*
* 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.examples.storage.user;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ExampleUserStorageProvider implements UserStorageProvider, UserLookupProvider, UserRegistrationProvider {
protected EntityManager em;
protected ComponentModel model;
protected KeycloakSession session;
public ExampleUserStorageProvider(EntityManager em, ComponentModel model, KeycloakSession session) {
this.em = em;
this.model = model;
this.session = session;
}
@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 close() {
em.close();
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
String persistenceId = StorageId.externalId(id);
UserEntity entity = em.find(UserEntity.class, persistenceId);
if (entity == null) return null;
return new UserAdapter(session, realm, model, entity);
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
TypedQuery<UserEntity> query = em.createNamedQuery("getUserByUsername", UserEntity.class);
query.setParameter("username", username);
List<UserEntity> result = query.getResultList();
if (result.isEmpty()) return null;
return new UserAdapter(session, realm, model, result.get(0));
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
TypedQuery<UserEntity> query = em.createNamedQuery("getUserByEmail", UserEntity.class);
query.setParameter("email", email);
List<UserEntity> result = query.getResultList();
if (result.isEmpty()) return null;
return new UserAdapter(session, realm, model, result.get(0));
}
@Override
public UserModel addUser(RealmModel realm, String username) {
UserEntity entity = new UserEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setUsername(username);
em.persist(entity);
return new UserAdapter(session, realm, model, entity);
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
String persistenceId = StorageId.externalId(user.getId());
UserEntity entity = em.find(UserEntity.class, persistenceId);
if (entity == null) return false;
em.remove(entity);
return true;
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
}
}

View file

@ -0,0 +1,60 @@
/*
* 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.examples.storage.user;
import org.keycloak.Config;
import org.keycloak.component.ComponentModel;
import org.keycloak.connections.jpa.JndiEntityManagerLookup;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.storage.UserStorageProviderFactory;
import javax.persistence.EntityManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ExampleUserStorageProviderFactory implements UserStorageProviderFactory<ExampleUserStorageProvider> {
protected String jndiName = "java:jboss/ExampleUserEntityManagerFactory";
@Override
public ExampleUserStorageProvider create(KeycloakSession session, ComponentModel model) {
EntityManager em = JndiEntityManagerLookup.getSessionEntityManager(session, jndiName);
return new ExampleUserStorageProvider(em, model, session);
}
@Override
public String getId() {
return "example-user-storage";
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,135 @@
/*
* 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.examples.storage.user;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserAdapter extends AbstractUserAdapterFederatedStorage {
protected UserEntity entity;
protected String keycloakId;
public UserAdapter(KeycloakSession session, RealmModel realm, ComponentModel model, UserEntity entity) {
super(session, realm, model);
this.entity = entity;
keycloakId = StorageId.keycloakId(model, entity.getId());
}
@Override
public String getUsername() {
return entity.getUsername();
}
@Override
public void setUsername(String username) {
entity.setUsername(username);
}
@Override
public void setEmail(String email) {
entity.setEmail(email);
}
@Override
public String getEmail() {
return entity.getEmail();
}
@Override
public String getId() {
return keycloakId;
}
@Override
public void updateCredential(UserCredentialModel cred) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
entity.setPassword(cred.getValue());
} else {
super.updateCredential(cred);
}
}
@Override
public void setSingleAttribute(String name, String value) {
if (name.equals("phone")) {
entity.setPhone(value);
} else {
super.setSingleAttribute(name, value);
}
}
@Override
public void removeAttribute(String name) {
if (name.equals("phone")) {
entity.setPhone(null);
} else {
super.removeAttribute(name);
}
}
@Override
public void setAttribute(String name, List<String> values) {
if (name.equals("phone")) {
entity.setPhone(values.get(0));
} else {
super.setAttribute(name, values);
}
}
@Override
public String getFirstAttribute(String name) {
if (name.equals("phone")) {
return entity.getPhone();
} else {
return super.getFirstAttribute(name);
}
}
@Override
public Map<String, List<String>> getAttributes() {
Map<String, List<String>> attrs = super.getAttributes();
MultivaluedHashMap<String, String> all = new MultivaluedHashMap<>();
all.putAll(attrs);
all.add("phone", entity.getPhone());
return all;
}
@Override
public List<String> getAttribute(String name) {
if (name.equals("phone")) {
List<String> phone = new LinkedList<>();
phone.add(entity.getPhone());
return phone;
} else {
return super.getAttribute(name);
}
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.examples.storage.user;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="getUserByUsername", query="select u from UserEntity u where u.username = :username"),
@NamedQuery(name="getUserByEmail", query="select u from UserEntity u where u.email = :email"),
})
@Entity
public class UserEntity {
@Id
private String id;
private String username;
private String email;
private String password;
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
<non-jta-data-source>java:jboss/datasources/ExampleUserDS</non-jta-data-source>
<class>org.keycloak.examples.storage.user.UserEntity</class>
<properties>
<property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/ExampleUserEntityManagerFactory" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>

View file

@ -0,0 +1 @@
org.keycloak.examples.storage.user.ExampleUserStorageProviderFactory

View file

@ -70,7 +70,7 @@ public abstract class TxAwareLDAPUserModelDelegate extends UserModelDelegate {
logger.trace("Starting and enlisting transaction for object " + ldapUser.getDn().toString());
}
this.provider.getSession().getTransaction().enlistAfterCompletion(transaction);
this.provider.getSession().getTransactionManager().enlistAfterCompletion(transaction);
}
}

View file

@ -163,7 +163,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
UserModel that = session.userStorage().getUserByEmail(email, realm);
if (that != null && !that.getId().equals(user.getId())) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
String exceptionMessage = String.format("Can't import user '%s' from LDAP because email '%s' already exists in Keycloak. Existing user with this email is '%s'", user.getUsername(), email, that.getUsername());
throw new ModelDuplicateException(exceptionMessage, UserModel.EMAIL);
}

View file

@ -40,7 +40,7 @@ public class InfinispanStoreFactoryProvider implements CachedStoreFactoryProvide
InfinispanStoreFactoryProvider(KeycloakSession delegate) {
this.session = delegate;
this.transaction = new CacheTransaction();
this.session.getTransaction().enlistAfterCompletion(transaction);
this.session.getTransactionManager().enlistAfterCompletion(transaction);
}
@Override

View file

@ -19,11 +19,10 @@ package org.keycloak.models.cache.infinispan;
import org.keycloak.Config;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.*;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.infinispan.entities.CachedRealm;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
@ -746,48 +745,6 @@ public class RealmAdapter implements RealmModel {
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
return updated.addStorageProvider(provider);
}
@Override
public void updateStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
updated.updateStorageProvider(provider);
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
updated.removeStorageProvider(provider);
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
getDelegateForUpdate();
updated.setStorageProviders(providers);
}
@Override
public List<StorageProviderModel> getStorageProviders() {
if (isUpdated()) return updated.getStorageProviders();
return cached.getStorageProviders();
}
@Override
public StorageProviderModel getStorageProvider(String id) {
if (isUpdated()) return updated.getStorageProvider(id);
for (StorageProviderModel model : cached.getStorageProviders()) {
if (model.getId().equals(id)) return model;
}
return null;
}
@Override
public String getLoginTheme() {
if (isUpdated()) return updated.getLoginTheme();
@ -1451,6 +1408,52 @@ public class RealmAdapter implements RealmModel {
return cacheSession.getClientTemplateById(id, this);
}
@Override
public ComponentModel addComponentModel(ComponentModel model) {
getDelegateForUpdate();
return updated.addComponentModel(model);
}
@Override
public void updateComponent(ComponentModel component) {
getDelegateForUpdate();
updated.updateComponent(component);
}
@Override
public void removeComponent(ComponentModel component) {
getDelegateForUpdate();
updated.removeComponent(component);
}
@Override
public void removeComponents(String parentId) {
getDelegateForUpdate();
updated.removeComponents(parentId);
}
@Override
public List<ComponentModel> getComponents(String parentId, String providerType) {
if (isUpdated()) return updated.getComponents(parentId, providerType);
List<ComponentModel> components = cached.getComponentsByParent().getList(parentId + providerType);
if (components == null) return Collections.EMPTY_LIST;
return Collections.unmodifiableList(components);
}
@Override
public List<ComponentModel> getComponents() {
if (isUpdated()) return updated.getComponents();
List<ComponentModel> results = new LinkedList<>();
results.addAll(cached.getComponents().values());
return Collections.unmodifiableList(results);
}
@Override
public ComponentModel getComponent(String id) {
if (isUpdated()) return updated.getComponent(id);
return cached.getComponents().get(id);
}
}

View file

@ -132,8 +132,8 @@ public class RealmCacheSession implements CacheRealmProvider {
this.cache = cache;
this.session = session;
this.startupRevision = cache.getCurrentCounter();
session.getTransaction().enlistPrepare(getPrepareTransaction());
session.getTransaction().enlistAfterCompletion(getAfterTransaction());
session.getTransactionManager().enlistPrepare(getPrepareTransaction());
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
}
public long getStartupRevision() {

View file

@ -19,6 +19,7 @@ package org.keycloak.models.cache.infinispan;
import org.jboss.logging.Logger;
import org.keycloak.common.constants.ServiceAccountConstants;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.FederatedIdentityModel;
@ -39,7 +40,6 @@ import org.keycloak.models.cache.infinispan.entities.CachedUser;
import org.keycloak.models.cache.infinispan.entities.CachedUserConsent;
import org.keycloak.models.cache.infinispan.entities.CachedUserConsents;
import org.keycloak.models.cache.infinispan.entities.UserListQuery;
import org.keycloak.storage.StorageProviderModel;
import java.util.*;
@ -65,7 +65,7 @@ public class UserCacheSession implements CacheUserProvider {
this.cache = cache;
this.session = session;
this.startupRevision = cache.getCurrentCounter();
session.getTransaction().enlistAfterCompletion(getTransaction());
session.getTransactionManager().enlistAfterCompletion(getTransaction());
}
@Override
@ -665,7 +665,8 @@ public class UserCacheSession implements CacheUserProvider {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel provider) {
getDelegate().preRemove(realm, provider);
public void preRemove(RealmModel realm, ComponentModel component) {
getDelegate().preRemove(realm, component);
}
}

View file

@ -18,6 +18,7 @@
package org.keycloak.models.cache.infinispan.entities;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel;
@ -29,20 +30,14 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.cache.infinispan.RealmCache;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.storage.StorageProviderModel;
import java.io.Serializable;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
@ -111,7 +106,8 @@ public class CachedRealm extends AbstractRevisioned {
protected List<RequiredCredentialModel> requiredCredentials;
protected List<UserFederationProviderModel> userFederationProviders;
protected List<StorageProviderModel> storageProviders;
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
protected Map<String, ComponentModel> components = new HashMap<>();
protected MultivaluedHashMap<String, UserFederationMapperModel> userFederationMappers = new MultivaluedHashMap<String, UserFederationMapperModel>();
protected Set<UserFederationMapperModel> userFederationMapperSet;
protected List<IdentityProviderModel> identityProviders;
@ -208,7 +204,6 @@ public class CachedRealm extends AbstractRevisioned {
requiredCredentials = model.getRequiredCredentials();
userFederationProviders = model.getUserFederationProviders();
storageProviders = model.getStorageProviders();
userFederationMapperSet = model.getUserFederationMappers();
for (UserFederationMapperModel mapper : userFederationMapperSet) {
this.userFederationMappers.add(mapper.getFederationProviderId(), mapper);
@ -279,6 +274,13 @@ public class CachedRealm extends AbstractRevisioned {
resetCredentialsFlow = model.getResetCredentialsFlow();
clientAuthenticationFlow = model.getClientAuthenticationFlow();
for (ComponentModel component : model.getComponents()) {
componentsByParent.add(component.getParentId() + component.getProviderType(), component);
}
for (ComponentModel component : model.getComponents()) {
components.put(component.getId(), component);
}
}
protected void cacheClientTemplates(RealmModel model) {
@ -602,7 +604,11 @@ public class CachedRealm extends AbstractRevisioned {
return requiredActionProviderList;
}
public List<StorageProviderModel> getStorageProviders() {
return storageProviders;
public MultivaluedHashMap<String, ComponentModel> getComponentsByParent() {
return componentsByParent;
}
public Map<String, ComponentModel> getComponents() {
return components;
}
}

View file

@ -81,7 +81,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
this.loginFailureCache = loginFailureCache;
this.tx = new InfinispanKeycloakTransaction();
session.getTransaction().enlistAfterCompletion(tx);
session.getTransactionManager().enlistAfterCompletion(tx);
}
protected Cache<String, SessionEntity> getCache(boolean offline) {

View file

@ -63,7 +63,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
EntityManager em = emf.createEntityManager();
em = PersistenceExceptionConverter.create(em);
session.getTransaction().enlist(new JpaKeycloakTransaction(em));
session.getTransactionManager().enlist(new JpaKeycloakTransaction(em));
return new DefaultJpaConnectionProvider(em);
}

View file

@ -14,20 +14,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.storage.changeset;
package org.keycloak.connections.jpa;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataCredentialValidator {
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
public class JndiEntityManagerLookup {
public static EntityManager getSessionEntityManager(KeycloakSession session, String entityManagerFactoryJndiName) {
EntityManagerFactory factory = null;
try {
factory = (EntityManagerFactory)new InitialContext().lookup(entityManagerFactoryJndiName);
} catch (NamingException e) {
throw new RuntimeException(e);
}
EntityManager em = factory.createEntityManager();
session.getTransactionManager().enlist(new JpaKeycloakTransaction(em));
return em;
}
}

View file

@ -34,7 +34,6 @@ import org.keycloak.models.jpa.entities.GroupEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
@ -128,9 +127,6 @@ public class JpaRealmProvider implements RealmProvider {
em.refresh(realm);
final RealmAdapter adapter = new RealmAdapter(session, em, realm);
session.users().preRemove(adapter);
for (StorageProviderModel provider : adapter.getStorageProviders()) {
adapter.removeStorageProvider(provider);
}
realm.getDefaultGroups().clear();
em.flush();
@ -141,6 +137,10 @@ public class JpaRealmProvider implements RealmProvider {
.setParameter("realm", realm).executeUpdate();
num = em.createNamedQuery("deleteGroupsByRealm")
.setParameter("realm", realm).executeUpdate();
num = em.createNamedQuery("deleteComponentConfigByRealm")
.setParameter("realm", realm).executeUpdate();
num = em.createNamedQuery("deleteComponentByRealm")
.setParameter("realm", realm).executeUpdate();
TypedQuery<String> query = em.createNamedQuery("getClientIdsByRealm", String.class);
query.setParameter("realm", realm.getId());

View file

@ -17,6 +17,7 @@
package org.keycloak.models.jpa;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.FederatedIdentityModel;
@ -42,7 +43,6 @@ import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.models.utils.DefaultRoles;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
@ -712,7 +712,7 @@ public class JpaUserProvider implements UserProvider {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
public void preRemove(RealmModel realm, ComponentModel component) {
}
}

View file

@ -18,7 +18,8 @@
package org.keycloak.models.jpa;
import org.jboss.logging.Logger;
import org.keycloak.connections.jpa.util.JpaUtils;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.jose.jwk.JWKBuilder;
import org.keycloak.models.AuthenticationExecutionModel;
@ -43,8 +44,6 @@ import org.keycloak.models.UserFederationProviderCreationEventImpl;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.jpa.entities.*;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderModel;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
@ -1003,179 +1002,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
return null;
}
@Override
public StorageProviderModel getStorageProvider(String id) {
StorageProviderEntity entity = em.find(StorageProviderEntity.class, id);
if (entity == null) return null;
return toModel(entity);
}
@Override
public List<StorageProviderModel> getStorageProviders() {
List<StorageProviderEntity> entities = realm.getStorageProviders();
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<StorageProviderEntity> copy = new LinkedList<>();
for (StorageProviderEntity entity : entities) {
copy.add(entity);
}
List<StorageProviderModel> result = new LinkedList<>();
for (StorageProviderEntity entity : copy) {
result.add(toModel(entity));
}
Collections.sort(result, StorageProviderModel.comparator);
return Collections.unmodifiableList(result);
}
protected StorageProviderModel toModel(StorageProviderEntity entity) {
StorageProviderModel model = new StorageProviderModel();
model.setId(entity.getId());
model.setProviderName(entity.getProviderName());
model.getConfig().putAll(entity.getConfig());
model.setPriority(entity.getPriority());
model.setDisplayName(entity.getDisplayName());
return model;
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), null, getStorageProviders());
String id = KeycloakModelUtils.generateId();
StorageProviderEntity entity = new StorageProviderEntity();
entity.setId(id);
entity.setRealm(realm);
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (model.getDisplayName() == null) {
displayName = id;
}
entity.setDisplayName(displayName);
em.persist(entity);
realm.getStorageProviders().add(entity);
em.flush();
StorageProviderModel providerModel = toModel(entity);
return providerModel;
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
session.users().preRemove(this, provider);
it.remove();
em.remove(entity);
return;
}
}
}
@Override
public void updateStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getStorageProviders());
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(model.getId())) {
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(model.getDisplayName());
}
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setPriority(model.getPriority());
break;
}
}
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
for (StorageProviderModel currentProvider : providers) {
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
}
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
boolean found = false;
for (StorageProviderModel model : providers) {
if (entity.getId().equals(model.getId())) {
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(displayName);
}
found = true;
break;
}
}
if (found) continue;
session.users().preRemove(this, toModel(entity));
removeFederationMappersForProvider(entity.getId());
it.remove();
em.remove(entity);
}
List<StorageProviderModel> add = new LinkedList<>();
for (StorageProviderModel model : providers) {
boolean found = false;
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(model.getId())) {
found = true;
break;
}
}
if (!found) add.add(model);
}
for (StorageProviderModel model : add) {
StorageProviderEntity entity = new StorageProviderEntity();
if (model.getId() != null) {
entity.setId(model.getId());
} else {
String id = KeycloakModelUtils.generateId();
entity.setId(id);
model.setId(id);
}
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
entity.setRealm(realm);
em.persist(entity);
realm.getStorageProviders().add(entity);
}
}
protected StorageProviderEntity getStorageProviderEntityById(String id) {
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(id)) {
return entity;
}
}
return null;
}
@Override
public RoleModel getRole(String name) {
return session.realms().getRealmRole(this, name);
@ -2280,4 +2106,131 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
return session.realms().getClientTemplateById(id, this);
}
@Override
public ComponentModel addComponentModel(ComponentModel model) {
ComponentEntity c = new ComponentEntity();
if (model.getId() == null) {
c.setId(KeycloakModelUtils.generateId());
} else {
c.setId(model.getId());
}
c.setName(model.getName());
c.setParentId(model.getParentId());
c.setProviderType(model.getProviderType());
c.setProviderId(model.getProviderId());
c.setRealm(realm);
em.persist(c);
setConfig(model, c);
model.setId(c.getId());
return model;
}
protected void setConfig(ComponentModel model, ComponentEntity c) {
for (String key : model.getConfig().keySet()) {
List<String> vals = model.getConfig().get(key);
for (String val : vals) {
ComponentConfigEntity config = new ComponentConfigEntity();
config.setId(KeycloakModelUtils.generateId());
config.setName(key);
config.setValue(val);
config.setComponent(c);
em.persist(config);
}
}
}
@Override
public void updateComponent(ComponentModel component) {
ComponentEntity c = em.find(ComponentEntity.class, component.getId());
if (c == null) return;
c.setName(component.getName());
c.setProviderId(component.getProviderId());
c.setProviderType(component.getProviderType());
c.setParentId(component.getParentId());
em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
em.flush();
setConfig(component, c);
}
@Override
public void removeComponent(ComponentModel component) {
ComponentEntity c = em.find(ComponentEntity.class, component.getId());
if (c == null) return;
session.users().preRemove(this, component);
em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
em.remove(c);
}
@Override
public void removeComponents(String parentId) {
TypedQuery<String> query = em.createNamedQuery("getComponentIdsByParent", String.class)
.setParameter("realm", realm)
.setParameter("parentId", parentId);
List<String> results = query.getResultList();
if (results.isEmpty()) return;
for (String id : results) {
session.users().preRemove(this, getComponent(id));
}
em.createNamedQuery("deleteComponentConfigByParent").setParameter("parentId", parentId).executeUpdate();
em.createNamedQuery("deleteComponentByParent").setParameter("parentId", parentId).executeUpdate();
}
@Override
public List<ComponentModel> getComponents(String parentId, String providerType) {
if (parentId == null) parentId = getId();
TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponentsByParentAndType", ComponentEntity.class)
.setParameter("realm", realm)
.setParameter("parentId", parentId)
.setParameter("providerType", providerType);
List<ComponentEntity> results = query.getResultList();
List<ComponentModel> rtn = new LinkedList<>();
for (ComponentEntity c : results) {
ComponentModel model = entityToModel(c);
rtn.add(model);
}
return rtn;
}
protected ComponentModel entityToModel(ComponentEntity c) {
ComponentModel model = new ComponentModel();
model.setId(c.getId());
model.setName(c.getName());
model.setProviderType(c.getProviderType());
model.setProviderId(c.getProviderId());
model.setParentId(c.getParentId());
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
TypedQuery<ComponentConfigEntity> configQuery = em.createNamedQuery("getComponentConfig", ComponentConfigEntity.class)
.setParameter("component", c);
List<ComponentConfigEntity> configResults = configQuery.getResultList();
for (ComponentConfigEntity configEntity : configResults) {
config.add(configEntity.getName(), configEntity.getValue());
}
model.setConfig(config);
return model;
}
@Override
public List<ComponentModel> getComponents() {
TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponents", ComponentEntity.class)
.setParameter("realm", realm);
List<ComponentEntity> results = query.getResultList();
List<ComponentModel> rtn = new LinkedList<>();
for (ComponentEntity c : results) {
ComponentModel model = entityToModel(c);
rtn.add(model);
}
return rtn;
}
@Override
public ComponentModel getComponent(String id) {
ComponentEntity c = em.find(ComponentEntity.class, id);
if (c == null) return null;
return entityToModel(c);
}
}

View file

@ -0,0 +1,110 @@
/*
* 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.models.jpa.entities;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="getComponentConfig", query="select attr from ComponentConfigEntity attr where attr.component = :component"),
@NamedQuery(name="deleteComponentConfigByComponent", query="delete from ComponentConfigEntity attr where attr.component = :component"),
@NamedQuery(name="deleteComponentConfigByRealm", query="delete from ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.realm=:realm)"),
@NamedQuery(name="deleteComponentConfigByParent", query="delete from ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.parentId=:parentId)"),
})
@Table(name="COMPONENT_CONFIG")
@Entity
public class ComponentConfigEntity {
@Id
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
protected String id;
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name = "COMPONENT_ID")
protected ComponentEntity component;
@Column(name = "NAME")
protected String name;
@Column(name = "VALUE")
protected String value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public ComponentEntity getComponent() {
return component;
}
public void setComponent(ComponentEntity component) {
this.component = component;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof ComponentConfigEntity)) return false;
ComponentConfigEntity that = (ComponentConfigEntity) o;
if (!id.equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -19,6 +19,7 @@ package org.keycloak.models.jpa.entities;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
@ -28,16 +29,28 @@ import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
@NamedQueries({
@NamedQuery(name="getComponents", query="select attr from ComponentEntity attr where attr.realm = :realm"),
@NamedQuery(name="getComponentsByParentAndType", query="select attr from ComponentEntity attr where attr.realm = :realm and attr.providerType = :providerType and attr.parentId = :parentId"),
@NamedQuery(name="getComponentIdsByParent", query="select attr.id from ComponentEntity attr where attr.realm = :realm and attr.parentId = :parentId"),
@NamedQuery(name="deleteComponentByRealm", query="delete from ComponentEntity c where c.realm = :realm"),
@NamedQuery(name="deleteComponentByParent", query="delete from ComponentEntity c where c.parentId = :parentId")
})
@Entity
@Table(name="STORAGE_PROVIDER")
public class StorageProviderEntity {
@Table(name="COMPONENT")
public class ComponentEntity {
@Id
@Column(name="ID", length = 36)
@ -48,19 +61,17 @@ public class StorageProviderEntity {
@JoinColumn(name = "REALM_ID")
protected RealmEntity realm;
@Column(name="PROVIDER_NAME")
private String providerName;
@Column(name="PRIORITY")
private int priority;
@Column(name="NAME")
protected String name;
@ElementCollection
@MapKeyColumn(name="name")
@Column(name="VALUE")
@CollectionTable(name="STORAGE_PROVIDER_CONFIG", joinColumns={ @JoinColumn(name="STORAGE_PROVIDER_ID") })
private Map<String, String> config;
@Column(name="PROVIDER_TYPE")
protected String providerType;
@Column(name="DISPLAY_NAME")
private String displayName;
@Column(name="PROVIDER_ID")
protected String providerId;
@Column(name="PARENT_ID")
protected String parentId;
public String getId() {
return id;
@ -70,6 +81,38 @@ public class StorageProviderEntity {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProviderType() {
return providerType;
}
public void setProviderType(String providerType) {
this.providerType = providerType;
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public RealmEntity getRealm() {
return realm;
}
@ -78,45 +121,13 @@ public class StorageProviderEntity {
this.realm = realm;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof StorageProviderEntity)) return false;
if (!(o instanceof ComponentEntity)) return false;
StorageProviderEntity that = (StorageProviderEntity) o;
ComponentEntity that = (ComponentEntity) o;
if (!id.equals(that.getId())) return false;

View file

@ -144,9 +144,6 @@ public class RealmEntity {
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
List<UserFederationProviderEntity> userFederationProviders = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
List<StorageProviderEntity> storageProviders = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<UserFederationMapperEntity> userFederationMappers = new ArrayList<UserFederationMapperEntity>();
@ -554,14 +551,6 @@ public class RealmEntity {
this.userFederationProviders = userFederationProviders;
}
public List<StorageProviderEntity> getStorageProviders() {
return storageProviders;
}
public void setStorageProviders(List<StorageProviderEntity> storageProviders) {
this.storageProviders = storageProviders;
}
public Collection<UserFederationMapperEntity> getUserFederationMappers() {
return userFederationMappers;
}

View file

@ -17,6 +17,7 @@
package org.keycloak.storage.jpa;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel;
@ -31,11 +32,10 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.CredentialEntity;
import org.keycloak.models.utils.FederatedCredentials;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.federated.UserAttributeFederatedStorage;
import org.keycloak.storage.federated.UserBrokerLinkFederatedStorage;
import org.keycloak.storage.federated.UserConsentFederatedStorage;
@ -719,7 +719,9 @@ public class JpaUserFederatedStorageProvider implements
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel model) {
public void preRemove(RealmModel realm, ComponentModel model) {
if (!model.getProviderType().equals(UserStorageProvider.class.getName())) return;
em.createNamedQuery("deleteBrokerLinkByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();

View file

@ -149,22 +149,26 @@
<column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="STORAGE_PROVIDER_CONFIG">
<column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(255)"/>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
<createTable tableName="STORAGE_PROVIDER">
<createTable tableName="COMPONENT_CONFIG">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="DISPLAY_NAME" type="VARCHAR(255)"/>
<column name="PRIORITY" type="INT"/>
<column name="PROVIDER_NAME" type="VARCHAR(255)"/>
<column name="COMPONENT_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(4096)"/>
</createTable>
<createTable tableName="COMPONENT">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="NAME" type="VARCHAR(255)"/>
<column name="PARENT_ID" type="VARCHAR(36)"/>
<column name="PROVIDER_ID" type="VARCHAR(36)"/>
<column name="PROVIDER_TYPE" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(36)"/>
</createTable>
@ -185,10 +189,10 @@
<addPrimaryKey columnNames="ROLE_ID, USER_ID" constraintName="CONSTR_FED_USER_ROLE" tableName="FED_USER_ROLE_MAPPING"/>
<addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTR_FED_REQUIRED_ACTION" tableName="FED_USER_REQUIRED_ACTION"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTR_STORAGE_PROVIDER_PK" tableName="STORAGE_PROVIDER"/>
<addPrimaryKey columnNames="STORAGE_PROVIDER_ID, NAME" constraintName="CONSTR_STORAGE_CONFIG" tableName="STORAGE_PROVIDER_CONFIG"/>
<!--
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="STORAGE_PROVIDER" constraintName="FK_STORAGE_PROVIDER_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
-->
<addPrimaryKey columnNames="ID" constraintName="CONSTR_COMPONENT_PK" tableName="COMPONENT"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTR_COMPONENT_CONFIG_PK" tableName="COMPONENT_CONFIG"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="COMPONENT" constraintName="FK_COMPONENT_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="COMPONENT_ID" baseTableName="COMPONENT_CONFIG" constraintName="FK_COMPONENT_CONFIG" referencedColumnNames="ID" referencedTableName="COMPONENT"/>
</changeSet>
</databaseChangeLog>

View file

@ -25,7 +25,8 @@
<class>org.keycloak.models.jpa.entities.RealmEntity</class>
<class>org.keycloak.models.jpa.entities.RealmAttributeEntity</class>
<class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
<class>org.keycloak.models.jpa.entities.StorageProviderEntity</class>
<class>org.keycloak.models.jpa.entities.ComponentConfigEntity</class>
<class>org.keycloak.models.jpa.entities.ComponentEntity</class>
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
<class>org.keycloak.models.jpa.entities.UserFederationMapperEntity</class>
<class>org.keycloak.models.jpa.entities.RoleEntity</class>

View file

@ -22,7 +22,6 @@ import java.net.UnknownHostException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLSocketFactory;
@ -142,7 +141,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
lazyInit(session);
TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
session.getTransactionManager().enlist(new MongoKeycloakTransaction(invocationContext));
return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
}

View file

@ -21,6 +21,7 @@ import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.component.ComponentModel;
import org.keycloak.connections.mongo.api.MongoStore;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.models.ClientModel;
@ -44,7 +45,6 @@ import org.keycloak.models.entities.UserConsentEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.storage.StorageProviderModel;
import java.util.ArrayList;
import java.util.Collections;
@ -632,7 +632,7 @@ public class MongoUserProvider implements UserProvider {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
public void preRemove(RealmModel realm, ComponentModel component) {
}
}

View file

@ -20,6 +20,8 @@ package org.keycloak.models.mongo.keycloak.adapters;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.jose.jwk.JWKBuilder;
@ -47,20 +49,18 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.entities.AuthenticationExecutionEntity;
import org.keycloak.models.entities.AuthenticationFlowEntity;
import org.keycloak.models.entities.AuthenticatorConfigEntity;
import org.keycloak.models.entities.ComponentEntity;
import org.keycloak.models.entities.IdentityProviderEntity;
import org.keycloak.models.entities.IdentityProviderMapperEntity;
import org.keycloak.models.entities.RequiredActionProviderEntity;
import org.keycloak.models.entities.RequiredCredentialEntity;
import org.keycloak.models.entities.StorageProviderEntity;
import org.keycloak.models.entities.UserFederationMapperEntity;
import org.keycloak.models.entities.UserFederationProviderEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
@ -1170,166 +1170,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
updateRealm();
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), null, getStorageProviders());
StorageProviderEntity entity = new StorageProviderEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
realm.getStorageProviders().add(entity);
updateRealm();
StorageProviderModel providerModel = new StorageProviderModel(entity.getId(), model.getProviderName(),
model.getConfig(), model.getPriority(), displayName);
return providerModel;
}
@Override
public void updateStorageProvider(StorageProviderModel provider) {
KeycloakModelUtils.ensureUniqueDisplayName(provider.getDisplayName(), provider, getStorageProviders());
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
entity.setProviderName(provider.getProviderName());
entity.setConfig(provider.getConfig());
entity.setPriority(provider.getPriority());
String displayName = provider.getDisplayName();
if (displayName != null) {
entity.setDisplayName(provider.getDisplayName());
}
}
}
updateRealm();
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
session.users().preRemove(this, new StorageProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName()
));
it.remove();
}
}
updateRealm();
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
for (StorageProviderModel currentProvider : providers) {
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
}
List<StorageProviderEntity> existingProviders = realm.getStorageProviders();
List<StorageProviderEntity> toRemove = new LinkedList<>();
for (StorageProviderEntity entity : existingProviders) {
boolean found = false;
for (StorageProviderModel model : providers) {
if (entity.getId().equals(model.getId())) {
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(displayName);
}
found = true;
break;
}
}
if (found) continue;
session.users().preRemove(this, new StorageProviderModel(entity.getId(), entity.getProviderName(),
entity.getConfig(), entity.getPriority(), entity.getDisplayName()));
toRemove.add(entity);
}
for (StorageProviderEntity entity : toRemove) {
realm.getStorageProviders().remove(entity);
}
List<StorageProviderModel> add = new LinkedList<>();
for (StorageProviderModel model : providers) {
boolean found = false;
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(model.getId())) {
found = true;
break;
}
}
if (!found) add.add(model);
}
for (StorageProviderModel model : add) {
StorageProviderEntity entity = new StorageProviderEntity();
if (model.getId() != null) {
entity.setId(model.getId());
} else {
String id = KeycloakModelUtils.generateId();
entity.setId(id);
model.setId(id);
}
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
realm.getStorageProviders().add(entity);
}
updateRealm();
}
@Override
public List<StorageProviderModel> getStorageProviders() {
List<StorageProviderEntity> entities = realm.getStorageProviders();
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<StorageProviderEntity> copy = new LinkedList<>();
for (StorageProviderEntity entity : entities) {
copy.add(entity);
}
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);
}
@Override
public StorageProviderModel getStorageProvider(String id) {
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(id)) return new StorageProviderModel(entity.getId(), entity.getProviderName(),
entity.getConfig(), entity.getPriority(), entity.getDisplayName());
}
return null;
}
@Override
public boolean isEventsEnabled() {
return realm.isEventsEnabled();
@ -2217,5 +2057,115 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
return model.getClientTemplateById(id, this);
}
@Override
public ComponentModel addComponentModel(ComponentModel model) {
ComponentEntity entity = new ComponentEntity();
if (model.getId() == null) {
entity.setId(KeycloakModelUtils.generateId());
} else {
entity.setId(model.getId());
}
entity.setConfig(model.getConfig());
entity.setId(model.getId());
entity.setParentId(model.getParentId());
entity.setProviderType(model.getProviderType());
entity.setProviderId(model.getProviderId());
entity.setName(model.getName());
model.setId(entity.getId());
realm.getComponentEntities().add(entity);
updateRealm();
return model;
}
@Override
public void updateComponent(ComponentModel model) {
for (ComponentEntity entity : realm.getComponentEntities()) {
if (entity.getId().equals(model.getId())) {
entity.setConfig(model.getConfig());
entity.setId(model.getId());
entity.setParentId(model.getParentId());
entity.setProviderType(model.getProviderType());
entity.setProviderId(model.getProviderId());
entity.setName(model.getName());
}
}
updateRealm();
}
@Override
public void removeComponent(ComponentModel component) {
Iterator<ComponentEntity> it = realm.getComponentEntities().iterator();
while(it.hasNext()) {
if (it.next().getId().equals(component.getId())) {
session.users().preRemove(this, component);
it.remove();
break;
}
}
updateRealm();
}
@Override
public void removeComponents(String parentId) {
Iterator<ComponentEntity> it = realm.getComponentEntities().iterator();
while(it.hasNext()) {
ComponentEntity next = it.next();
if (next.getParentId().equals(parentId)) {
session.users().preRemove(this, entityToModel(next));
it.remove();
}
}
updateRealm();
}
@Override
public List<ComponentModel> getComponents(String parentId, String providerType) {
List<ComponentModel> results = new LinkedList<>();
for (ComponentEntity entity : realm.getComponentEntities()) {
if (entity.getParentId().equals(parentId) && entity.getProviderType().equals(providerType)) {
ComponentModel model = entityToModel(entity);
results.add(model);
}
}
return results;
}
protected ComponentModel entityToModel(ComponentEntity entity) {
ComponentModel model = new ComponentModel();
model.setId(entity.getId());
model.setName(entity.getName());
model.setParentId(entity.getParentId());
model.setProviderId(entity.getProviderId());
model.setProviderType(entity.getProviderType());
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<>();
map.putAll(entity.getConfig());
model.setConfig(map);
return model;
}
@Override
public List<ComponentModel> getComponents() {
List<ComponentModel> results = new LinkedList<>();
for (ComponentEntity entity : realm.getComponentEntities()) {
ComponentModel model = entityToModel(entity);
results.add(model);
}
return results;
}
@Override
public ComponentModel getComponent(String id) {
for (ComponentEntity entity : realm.getComponentEntities()) {
if (entity.getId() == entity.getId()) {
return entityToModel(entity);
}
}
return null;
}
}

View file

@ -14,41 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.storage;
package org.keycloak.component;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ConfiguredProvider;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.storage.UserStorageProviderModel;
import java.util.Set;
import java.util.Collections;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface StorageProviderFactory<T extends StorageProvider> extends ProviderFactory<StorageProvider> {
/**
* called per Keycloak transaction.
*
* @param session
* @param model
* @return
*/
T getInstance(KeycloakSession session, StorageProviderModel model);
public interface ComponentFactory<CreatedType, ProviderType extends Provider> extends ProviderFactory<ProviderType>, ConfiguredProvider {
CreatedType create(KeycloakSession session, ComponentModel model);
/**
* This is the name of the provider and will be showed in the admin console as an option.
*
* @return
*/
@Override
String getId();
default ProviderType create(KeycloakSession session) {
return null;
}
void validateConfiguration(KeycloakSession session, ComponentModel config) throws ComponentValidationException;
/**
* This method is never called and is only an artifact of ProviderFactory. Returning null with no implementation is recommended.
* @param session
* @return
*/
@Override
StorageProvider create(KeycloakSession session);
}

View file

@ -0,0 +1,101 @@
/*
* 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.component;
import org.keycloak.common.util.MultivaluedHashMap;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Stored configuration of a User Storage provider instance.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
public class ComponentModel implements Serializable {
private String id;
private String name;
private String providerId;
private String providerType;
private String parentId;
private MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
public ComponentModel() {}
public ComponentModel(ComponentModel copy) {
this.id = copy.id;
this.name = copy.name;
this.providerId = copy.providerId;
this.providerType = copy.providerType;
this.config = copy.config;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MultivaluedHashMap<String, String> getConfig() {
return config;
}
public void setConfig(MultivaluedHashMap<String, String> config) {
this.config = config;
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getProviderType() {
return providerType;
}
public void setProviderType(String providerType) {
this.providerType = providerType;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
}

View file

@ -14,26 +14,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.storage;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
package org.keycloak.component;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface StorageProvider extends Provider {
public class ComponentValidationException extends RuntimeException {
public ComponentValidationException() {
}
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm, StorageProviderModel model);
public ComponentValidationException(String message) {
super(message);
}
public ComponentValidationException(String message, Throwable cause) {
super(message, cause);
}
public ComponentValidationException(Throwable cause) {
super(cause);
}
public ComponentValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View file

@ -14,18 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.storage.changeset;
package org.keycloak.component;
import org.keycloak.models.RealmModel;
import org.keycloak.models.entities.UserEntity;
import org.keycloak.storage.StorageId;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ConfiguredProvider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataLookup {
UserData getUserById(RealmModel realm, StorageId id);
UserData getUserByUsername(RealmModel realm, String username);
UserData getUserByEmail(RealmModel realm, String email);
public interface ConfiguredComponent extends ConfiguredProvider {
}

View file

@ -32,16 +32,48 @@ public interface KeycloakSession {
KeycloakContext getContext();
KeycloakTransactionManager getTransaction();
KeycloakTransactionManager getTransactionManager();
/**
* Get dedicated provider instance of provider type clazz that was created for this session. If one hasn't been created yet,
* find the factory and allocate by calling ProviderFactory.create(KeycloakSession). The provider to use is determined
* by the "provider" config entry in keycloak-server boot configuration. (keycloak-server.json)
*
*
*
* @param clazz
* @param <T>
* @return
*/
<T extends Provider> T getProvider(Class<T> clazz);
/**
* Get dedicated provider instance for a specific provider factory of id of provider type clazz that was created for this session.
* If one hasn't been created yet,
* find the factory and allocate by calling ProviderFactory.create(KeycloakSession).
* @param clazz
* @param id
* @param <T>
* @return
*/
<T extends Provider> T getProvider(Class<T> clazz, String id);
/**
* Get all provider factories that manage provider instances of class.
*
* @param clazz
* @param <T>
* @return
*/
<T extends Provider> Set<String> listProviderIds(Class<T> clazz);
<T extends Provider> Set<T> getAllProviders(Class<T> clazz);
Object getAttribute(String attribute);
Object removeAttribute(String attribute);
void setAttribute(String name, Object value);
void enlistForClose(Provider provider);
KeycloakSessionFactory getKeycloakSessionFactory();
@ -69,22 +101,40 @@ public interface KeycloakSession {
void close();
/**
* Possibly both cached and federated view of users depending on configuration.
* A cached view of all users in system.
*
* @return
*/
UserFederationManager users();
/**
* Un-cached view of all users in system that does NOT include users available from the deprecated UserFederationProvider SPI.
*
* @return
*/
UserProvider userStorageManager();
/**
* Keycloak user storage. Non-federated, but possibly cache (if it is on) view of users.
* A cached view of all users in system that does NOT include users available from the deprecated UserFederationProvider SPI.
*/
UserProvider userStorage();
UserFederatedStorageProvider userFederatedStorage();
/**
* Keycloak specific local storage for users. No cache in front, this api talks directly to database.
*
* @return
*/
UserProvider userLocalStorage();
/**
* Hybrid storage for UserStorageProviders that can't store a specific piece of keycloak data in their external storage.
*
* @return
*/
UserFederatedStorageProvider userFederatedStorage();
/**
* Keycloak scripting support.
*/

View file

@ -18,13 +18,17 @@
package org.keycloak.models;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.component.ComponentModel;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -282,12 +286,23 @@ public interface RealmModel extends RoleContainerModel {
public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name);
StorageProviderModel addStorageProvider(StorageProviderModel model);
void updateStorageProvider(StorageProviderModel provider);
void removeStorageProvider(StorageProviderModel provider);
void setStorageProviders(List<StorageProviderModel> providers);
List<StorageProviderModel> getStorageProviders();
StorageProviderModel getStorageProvider(String id);
ComponentModel addComponentModel(ComponentModel model);
void updateComponent(ComponentModel component);
void removeComponent(ComponentModel component);
void removeComponents(String parentId);
List<ComponentModel> getComponents(String parentId, String providerType);
List<ComponentModel> getComponents();
ComponentModel getComponent(String id);
default
List<UserStorageProviderModel> getUserStorageProviders() {
List<UserStorageProviderModel> list = new LinkedList<>();
for (ComponentModel component : getComponents(getId(), UserStorageProvider.class.getName())) {
list.add(new UserStorageProviderModel(component));
}
Collections.sort(list, UserStorageProviderModel.comparator);
return list;
}
// Should return list sorted by UserFederationProviderModel.priority
List<UserFederationProviderModel> getUserFederationProviders();

View file

@ -18,11 +18,11 @@
package org.keycloak.models;
import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.policy.PasswordPolicyManagerProvider;
import org.keycloak.policy.PolicyError;
import org.keycloak.services.managers.UserManager;
import org.keycloak.storage.StorageProviderModel;
import java.util.ArrayList;
import java.util.Arrays;
@ -487,11 +487,6 @@ public class UserFederationManager implements UserProvider {
session.userStorage().preRemove(protocolMapper);
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (realm.getPasswordPolicy() != null) {
@ -604,6 +599,11 @@ public class UserFederationManager implements UserProvider {
return (result != null) ? result : CredentialValidationOutput.failed();
}
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
}
@Override
public void close() {
}

View file

@ -17,8 +17,8 @@
package org.keycloak.models;
import org.keycloak.component.ComponentModel;
import org.keycloak.provider.Provider;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
@ -56,10 +56,20 @@ public interface UserProvider extends Provider,
List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts);
/**
* only used for local storage
*
* @param realm
* @param id
* @param username
* @param addDefaultRoles
* @param addDefaultRequiredActions
* @return
*/
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, UserFederationProviderModel link);
void preRemove(RealmModel realm, StorageProviderModel link);
void preRemove(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm, GroupModel group);
@ -73,4 +83,6 @@ public interface UserProvider extends Provider,
void close();
void preRemove(RealmModel realm, ComponentModel component);
}

View file

@ -0,0 +1,75 @@
/*
* 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.models.entities;
import org.keycloak.common.util.MultivaluedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ComponentEntity extends AbstractIdentifiableEntity {
protected String name;
protected String providerType;
protected String providerId;
protected String parentId;
protected Map<String, List<String>> config = new MultivaluedHashMap<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProviderType() {
return providerType;
}
public void setProviderType(String providerType) {
this.providerType = providerType;
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public Map<String, List<String>> getConfig() {
return config;
}
public void setConfig(Map<String, List<String>> config) {
this.config = config;
}
}

View file

@ -85,7 +85,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private List<String> defaultGroups = new LinkedList<String>();
private List<RequiredCredentialEntity> requiredCredentials = new LinkedList<>();
private List<StorageProviderEntity> storageProviders = new LinkedList<>();
private List<ComponentEntity> componentEntities = new LinkedList<>();
private List<UserFederationProviderEntity> userFederationProviders = new LinkedList<UserFederationProviderEntity>();
private List<UserFederationMapperEntity> userFederationMappers = new LinkedList<UserFederationMapperEntity>();
private List<IdentityProviderEntity> identityProviders = new LinkedList<IdentityProviderEntity>();
@ -685,12 +685,12 @@ public class RealmEntity extends AbstractIdentifiableEntity {
this.defaultGroups = defaultGroups;
}
public List<StorageProviderEntity> getStorageProviders() {
return storageProviders;
public List<ComponentEntity> getComponentEntities() {
return componentEntities;
}
public void setStorageProviders(List<StorageProviderEntity> storageProviders) {
this.storageProviders = storageProviders;
public void setComponentEntities(List<ComponentEntity> componentEntities) {
this.componentEntities = componentEntities;
}
}

View file

@ -44,7 +44,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.storage.StorageProviderModel;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
@ -282,7 +281,7 @@ public final class KeycloakModelUtils {
*/
public static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakSessionTask task) {
KeycloakSession session = factory.create();
KeycloakTransaction tx = session.getTransaction();
KeycloakTransaction tx = session.getTransactionManager();
try {
tx.begin();
task.run(session);
@ -342,43 +341,6 @@ public final class KeycloakModelUtils {
}
// USER FEDERATION RELATED STUFF
/**
* Ensure that displayName of myProvider (if not null) is unique and there is no other provider with same displayName in the list.
*
* @param displayName to check for duplications
* @param myProvider provider, which is excluded from the list (if present)
* @param federationProviders
* @throws ModelDuplicateException if there is other provider with same displayName
*/
public static void ensureUniqueDisplayName(String displayName, StorageProviderModel myProvider, List<StorageProviderModel> federationProviders) throws ModelDuplicateException {
if (displayName != null) {
for (StorageProviderModel federationProvider : federationProviders) {
if (myProvider != null && (myProvider.equals(federationProvider) || (myProvider.getId() != null && myProvider.getId().equals(federationProvider.getId())))) {
continue;
}
if (displayName.equals(federationProvider.getDisplayName())) {
throw new ModelDuplicateException("There is already existing federation provider with display name: " + displayName);
}
}
}
}
public static StorageProviderModel findStorageProviderByDisplayName(String displayName, RealmModel realm) {
if (displayName == null) {
return null;
}
for (StorageProviderModel provider : realm.getStorageProviders()) {
if (displayName.equals(provider.getDisplayName())) {
return provider;
}
}
return null;
}
/**
* Ensure that displayName of myProvider (if not null) is unique and there is no other provider with same displayName in the list.
*

View file

@ -17,6 +17,7 @@
package org.keycloak.models.utils;
import org.keycloak.component.ComponentModel;
import org.keycloak.events.Event;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.admin.AuthDetails;
@ -44,6 +45,7 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.AuthDetailsRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
@ -51,6 +53,8 @@ import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@ -736,4 +740,27 @@ public class ModelToRepresentation {
return rep;
}
public static List<ConfigPropertyRepresentation> toRepresentation(List<ProviderConfigProperty> configProperties) {
List<ConfigPropertyRepresentation> propertiesRep = new LinkedList<>();
for (ProviderConfigProperty prop : configProperties) {
ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
propRep.setName(prop.getName());
propRep.setLabel(prop.getLabel());
propRep.setType(prop.getType());
propRep.setDefaultValue(prop.getDefaultValue());
propRep.setHelpText(prop.getHelpText());
propertiesRep.add(propRep);
}
return propertiesRep;
}
public static ComponentRepresentation toRepresentation(ComponentModel component) {
ComponentRepresentation rep = new ComponentRepresentation();
rep.setId(component.getId());
rep.setName(component.getName());
rep.setProviderId(component.getProviderId());
rep.setProviderType(component.getProviderType());
rep.setConfig(component.getConfig());
return rep;
}
}

View file

@ -20,6 +20,7 @@ package org.keycloak.models.utils;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.component.ComponentModel;
import org.keycloak.hash.Pbkdf2PasswordHashProvider;
import org.keycloak.migration.migrators.MigrationUtils;
import org.keycloak.models.ClientTemplateModel;
@ -62,6 +63,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.ClaimRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
@ -1618,4 +1620,13 @@ public class RepresentationToModel {
}
public static ComponentModel toModel(ComponentRepresentation rep) {
ComponentModel model = new ComponentModel();
model.setParentId(rep.getParentId());
model.setProviderType(rep.getProviderType());
model.setProviderId(rep.getProviderId());
model.setConfig(rep.getConfig());
model.setName(rep.getName());
return model;
}
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.storage;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.UserModel;
import java.io.Serializable;
@ -27,27 +28,44 @@ import java.io.Serializable;
public class StorageId implements Serializable {
private String id;
private String providerId;
private String storageId;
private String externalId;
public StorageId(String id) {
this.id = id;
if (!id.startsWith("f:")) {
storageId = id;
externalId = id;
return;
}
int providerIndex = id.indexOf(':', 2);
providerId = id.substring(2, providerIndex);
storageId = id.substring(providerIndex + 1);
externalId = id.substring(providerIndex + 1);
}
public StorageId(String providerId, String storageId) {
this.id = "f:" + providerId + ":" + storageId;
public StorageId(String providerId, String externalId) {
this.id = "f:" + providerId + ":" + externalId;
this.providerId = providerId;
this.storageId = storageId;
this.externalId = externalId;
}
/**
* generate the id string that should be returned by UserModel.getId()
*
* @param model
* @param externalId id used to resolve user in external storage
* @return
*/
public static String keycloakId(ComponentModel model, String externalId) {
return new StorageId(model.getId(), externalId).getId();
}
public static String externalId(String keycloakId) {
return new StorageId(keycloakId).getExternalId();
}
public static String resolveProviderId(UserModel user) {
return new StorageId(user.getId()).getProviderId();
}
@ -63,8 +81,8 @@ public class StorageId implements Serializable {
return providerId;
}
public String getStorageId() {
return storageId;
public String getExternalId() {
return externalId;
}

View file

@ -1,97 +0,0 @@
/*
* 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.storage;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/**
* Stored configuration of a User Storage provider instance.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
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>();
private int priority;
private String displayName;
public StorageProviderModel() {}
public StorageProviderModel(String id, String providerName, Map<String, String> config, int priority, String displayName) {
this.id = id;
this.providerName = providerName;
if (config != null) {
this.config.putAll(config);
}
this.priority = priority;
this.displayName = displayName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}

View file

@ -19,6 +19,7 @@ package org.keycloak.storage;
import org.jboss.logging.Logger;
import org.keycloak.common.util.reflections.Types;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.FederatedIdentityModel;
@ -62,10 +63,6 @@ public class UserStorageManager implements UserProvider {
protected KeycloakSession session;
// Set of already validated/proxied federation users during this session. Key is user ID
private Map<String, UserModel> managedUsers = new HashMap<>();
private UserProvider localStorage = null;
public UserStorageManager(KeycloakSession session) {
this.session = session;
}
@ -74,28 +71,37 @@ public class UserStorageManager implements UserProvider {
return session.userLocalStorage();
}
protected List<StorageProviderModel> getStorageProviders(RealmModel realm) {
return realm.getStorageProviders();
protected List<UserStorageProviderModel> getStorageProviders(RealmModel realm) {
return realm.getUserStorageProviders();
}
protected <T> T getFirstStorageProvider(RealmModel realm, Class<T> type) {
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
for (UserStorageProviderModel model : getStorageProviders(realm)) {
UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
if (Types.supports(type, factory, StorageProviderFactory.class)) {
return type.cast(factory.getInstance(session, model));
if (Types.supports(type, factory, UserStorageProviderFactory.class)) {
return type.cast(getStorageProviderInstance(model, factory));
}
}
return null;
}
private UserStorageProvider getStorageProviderInstance(UserStorageProviderModel model, UserStorageProviderFactory factory) {
UserStorageProvider instance = (UserStorageProvider)session.getAttribute(model.getId());
if (instance != null) return instance;
instance = factory.create(session, model);
session.enlistForClose(instance);
session.setAttribute(model.getId(), instance);
return instance;
}
protected <T> List<T> getStorageProviders(RealmModel realm, Class<T> type) {
List<T> list = new LinkedList<>();
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (Types.supports(type, factory, StorageProviderFactory.class)) {
list.add(type.cast(factory.getInstance(session, model)));
for (UserStorageProviderModel model : getStorageProviders(realm)) {
UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
if (Types.supports(type, factory, UserStorageProviderFactory.class)) {
list.add(type.cast(getStorageProviderInstance(model, factory)));
}
@ -106,10 +112,6 @@ public class UserStorageManager implements UserProvider {
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserRegistrationProvider registry = getFirstStorageProvider(realm, UserRegistrationProvider.class);
if (registry != null) {
return registry.addUser(realm, id, username, addDefaultRoles, addDefaultRequiredActions);
}
return localStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
}
@ -122,14 +124,14 @@ public class UserStorageManager implements UserProvider {
return localStorage().addUser(realm, username.toLowerCase());
}
public StorageProvider getStorageProvider(RealmModel realm, String providerId) {
StorageProviderModel model = realm.getStorageProvider(providerId);
public UserStorageProvider getStorageProvider(RealmModel realm, String componentId) {
ComponentModel model = realm.getComponent(componentId);
if (model == null) return null;
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
if (factory == null) {
throw new ModelException("Could not find StorageProviderFactory for: " + model.getProviderName());
throw new ModelException("Could not find UserStorageProviderFactory for: " + model.getProviderId());
}
return factory.getInstance(session, model);
return getStorageProviderInstance(new UserStorageProviderModel(model), factory);
}
@Override
@ -481,7 +483,7 @@ public class UserStorageManager implements UserProvider {
public void preRemove(RealmModel realm) {
localStorage().preRemove(realm);
getFederatedStorage().preRemove(realm);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
provider.preRemove(realm);
}
}
@ -496,7 +498,7 @@ public class UserStorageManager implements UserProvider {
public void preRemove(RealmModel realm, GroupModel group) {
localStorage().preRemove(realm, group);
getFederatedStorage().preRemove(realm, group);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
provider.preRemove(realm, group);
}
}
@ -505,7 +507,7 @@ public class UserStorageManager implements UserProvider {
public void preRemove(RealmModel realm, RoleModel role) {
localStorage().preRemove(realm, role);
getFederatedStorage().preRemove(realm, role);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
provider.preRemove(realm, role);
}
}
@ -557,7 +559,7 @@ public class UserStorageManager implements UserProvider {
if (toValidate.isEmpty()) return true;
StorageProvider provider = getStorageProvider(realm, StorageId.resolveProviderId(user));
UserStorageProvider provider = getStorageProvider(realm, StorageId.resolveProviderId(user));
if (!(provider instanceof UserCredentialValidatorProvider)) {
return false;
}
@ -601,7 +603,7 @@ public class UserStorageManager implements UserProvider {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
public void preRemove(RealmModel realm, ComponentModel component) {
}

View file

@ -16,13 +16,18 @@
*/
package org.keycloak.storage;
import org.keycloak.models.GroupModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserStorageProvider {
public interface UserStorageProvider extends Provider {
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, RoleModel role);
}

View file

@ -0,0 +1,85 @@
/*
* 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.storage;
import org.keycloak.Config;
import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.component.ComponentValidationException;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.Collections;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserStorageProviderFactory<T extends UserStorageProvider> extends ComponentFactory<T, UserStorageProvider> {
/**
* called per Keycloak transaction.
*
* @param session
* @param model
* @return
*/
T create(KeycloakSession session, ComponentModel model);
/**
* This is the name of the provider and will be showed in the admin console as an option.
*
* @return
*/
@Override
String getId();
@Override
default void init(Config.Scope config) {
}
@Override
default void postInit(KeycloakSessionFactory factory) {
}
@Override
default void close() {
}
@Override
default String getHelpText() {
return "";
}
@Override
default List<ProviderConfigProperty> getConfigProperties() {
return Collections.EMPTY_LIST;
}
@Override
default void validateConfiguration(KeycloakSession session, ComponentModel config) throws ComponentValidationException {
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.storage;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.RealmModel;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/**
* Stored configuration of a User Storage provider instance.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
public class UserStorageProviderModel extends ComponentModel {
public static Comparator<UserStorageProviderModel> comparator = new Comparator<UserStorageProviderModel>() {
@Override
public int compare(UserStorageProviderModel o1, UserStorageProviderModel o2) {
return o1.getPriority() - o2.getPriority();
}
};
public UserStorageProviderModel() {
setProviderType(UserStorageProvider.class.getName());
}
public UserStorageProviderModel(ComponentModel copy) {
super(copy);
}
public int getPriority() {
String priority = getConfig().getFirst("priority");
if (priority == null) return 0;
return Integer.valueOf(priority);
}
public void setPriority(int priority) {
getConfig().putSingle("priority", Integer.toString(priority));
}
}

View file

@ -24,7 +24,7 @@ import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class StorageProviderSpi implements Spi {
public class UserStorageProviderSpi implements Spi {
@Override
public boolean isInternal() {
@ -38,12 +38,12 @@ public class StorageProviderSpi implements Spi {
@Override
public Class<? extends Provider> getProviderClass() {
return StorageProvider.class;
return UserStorageProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return StorageProviderFactory.class;
return UserStorageProviderFactory.class;
}
}

View file

@ -17,6 +17,7 @@
package org.keycloak.storage.adapter;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
@ -29,7 +30,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.utils.DefaultRoles;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProviderModel;
import java.util.Collections;
import java.util.HashSet;
@ -58,9 +58,9 @@ public abstract class AbstractUserAdapter implements UserModel {
}
protected KeycloakSession session;
protected RealmModel realm;
protected StorageProviderModel storageProviderModel;
protected ComponentModel storageProviderModel;
public AbstractUserAdapter(KeycloakSession session, RealmModel realm, StorageProviderModel storageProviderModel) {
public AbstractUserAdapter(KeycloakSession session, RealmModel realm, ComponentModel storageProviderModel) {
this.session = session;
this.realm = realm;
this.storageProviderModel = storageProviderModel;

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.storage.adapter;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
@ -28,11 +29,9 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.utils.DefaultRoles;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -60,9 +59,9 @@ public abstract class AbstractUserAdapterFederatedStorage implements UserModel {
protected KeycloakSession session;
protected RealmModel realm;
protected StorageProviderModel storageProviderModel;
protected ComponentModel storageProviderModel;
public AbstractUserAdapterFederatedStorage(KeycloakSession session, RealmModel realm, StorageProviderModel storageProviderModel) {
public AbstractUserAdapterFederatedStorage(KeycloakSession session, RealmModel realm, ComponentModel storageProviderModel) {
this.session = session;
this.realm = realm;
this.storageProviderModel = storageProviderModel;

View file

@ -1,46 +0,0 @@
/*
* 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.storage.changeset;
import org.keycloak.models.RealmModel;
import org.keycloak.models.entities.UserEntity;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataQuery {
// Service account is included for counts
int getUsersCount(RealmModel realm);
List<UserData> getUsers(RealmModel realm);
List<UserData> searchForUser(String search, RealmModel realm);
List<UserData> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
List<UserData> getUsers(RealmModel realm, int firstResult, int maxResults);
List<UserData> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
List<UserData> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults);
// Searching by UserModel.attribute (not property)
List<UserData> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
}

View file

@ -1,32 +0,0 @@
/*
* 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.storage.changeset;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.entities.UserEntity;
import org.keycloak.storage.StorageId;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataStore {
void updateUser(RealmModel realm, UserData user);
void addUser(RealmModel realm, UserData user);
boolean removeUser(RealmModel realm, StorageId store);
}

View file

@ -17,6 +17,7 @@
package org.keycloak.storage.federated;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.ProtocolMapperModel;
@ -25,7 +26,6 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
import org.keycloak.storage.StorageProviderModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -44,7 +44,7 @@ public interface UserFederatedStorageProvider extends Provider,
void preRemove(RealmModel realm, UserFederationProviderModel link);
public void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, RoleModel role);
@ -54,5 +54,5 @@ public interface UserFederatedStorageProvider extends Provider,
void preRemove(RealmModel realm, UserModel user);
void preRemove(RealmModel realm, StorageProviderModel model);
void preRemove(RealmModel realm, ComponentModel model);
}

View file

@ -20,8 +20,6 @@ package org.keycloak.storage.federated;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>

View file

@ -25,7 +25,6 @@ import org.keycloak.models.UserModel;
* @version $Revision: 1 $
*/
public interface UserRegistrationProvider {
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
UserModel addUser(RealmModel realm, String username);

View file

@ -16,7 +16,7 @@
#
org.keycloak.models.UserFederationSpi
org.keycloak.storage.StorageProviderSpi
org.keycloak.storage.UserStorageProviderSpi
org.keycloak.storage.federated.UserFederatedStorageProviderSpi
org.keycloak.mappers.UserFederationMapperSpi
org.keycloak.models.RealmSpi

View file

@ -62,7 +62,7 @@ public class PartialImportManager {
try {
partialImport.prepare(rep, realm, session);
} catch (ErrorResponseException error) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
if (session.getTransactionManager().isActive()) session.getTransactionManager().setRollbackOnly();
return error.getResponse();
}
}
@ -72,7 +72,7 @@ public class PartialImportManager {
partialImport.removeOverwrites(realm, session);
results.addAllResults(partialImport.doImport(rep, realm, session));
} catch (ErrorResponseException error) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
if (session.getTransactionManager().isActive()) session.getTransactionManager().setRollbackOnly();
return error.getResponse();
}
}
@ -84,8 +84,8 @@ public class PartialImportManager {
}
}
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().commit();
}
return Response.ok(results).build();

View file

@ -36,6 +36,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
private final Map<Integer, Provider> providers = new HashMap<>();
private final List<Provider> closable = new LinkedList<Provider>();
private final DefaultKeycloakTransactionManager transactionManager;
private final Map<String, Object> attributes = new HashMap<>();
private RealmProvider model;
private UserProvider userModel;
private UserStorageManager userStorageManager;
@ -81,7 +82,22 @@ public class DefaultKeycloakSession implements KeycloakSession {
}
@Override
public KeycloakTransactionManager getTransaction() {
public Object getAttribute(String attribute) {
return attributes.get(attribute);
}
@Override
public Object removeAttribute(String attribute) {
return attributes.remove(attribute);
}
@Override
public void setAttribute(String name, Object value) {
attributes.put(name, value);
}
@Override
public KeycloakTransactionManager getTransactionManager() {
return transactionManager;
}

View file

@ -82,7 +82,7 @@ public class KeycloakSessionServletFilter implements Filter {
session.getContext().setConnection(connection);
ResteasyProviderFactory.pushContext(ClientConnection.class, connection);
KeycloakTransaction tx = session.getTransaction();
KeycloakTransaction tx = session.getTransactionManager();
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
tx.begin();
@ -123,8 +123,8 @@ public class KeycloakSessionServletFilter implements Filter {
private void closeSession(KeycloakSession session) {
// KeycloakTransactionCommitter is responsible for committing the transaction, but if an exception is thrown it's not invoked and transaction
// should be rolled back
if (session.getTransaction() != null && session.getTransaction().isActive()) {
session.getTransaction().rollback();
if (session.getTransactionManager() != null && session.getTransactionManager().isActive()) {
session.getTransactionManager().rollback();
}
session.close();

View file

@ -177,7 +177,7 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
queue.drainTo(events, TRANSACTION_SIZE);
Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this.
KeycloakSession session = factory.create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
for (LoginEvent event : events) {
if (event instanceof FailedLogin) {
@ -186,9 +186,9 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
run = false;
}
}
session.getTransaction().commit();
session.getTransactionManager().commit();
} catch (Exception e) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
throw e;
} finally {
for (LoginEvent event : events) {

View file

@ -835,17 +835,17 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private void fireErrorEvent(String message, Throwable throwable) {
if (!this.event.getEvent().getType().toString().endsWith("_ERROR")) {
boolean newTransaction = !this.session.getTransaction().isActive();
boolean newTransaction = !this.session.getTransactionManager().isActive();
try {
if (newTransaction) {
this.session.getTransaction().begin();
this.session.getTransactionManager().begin();
}
this.event.error(message);
if (newTransaction) {
this.session.getTransaction().commit();
this.session.getTransactionManager().commit();
}
} catch (Exception e) {
logger.couldNotFireEvent(e);
@ -869,8 +869,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
private void rollback() {
if (this.session.getTransaction().isActive()) {
this.session.getTransaction().rollback();
if (this.session.getTransactionManager().isActive()) {
this.session.getTransactionManager().rollback();
}
}

View file

@ -119,10 +119,10 @@ public class KeycloakApplication extends Application {
boolean bootstrapAdminUser = false;
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
bootstrapAdminUser = new ApplianceBootstrap(session).isNoMasterUser();
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}
@ -142,7 +142,7 @@ public class KeycloakApplication extends Application {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
exportImportManager = new ExportImportManager(session);
@ -155,10 +155,10 @@ public class KeycloakApplication extends Application {
if (createMasterRealm) {
applianceBootstrap.createMasterRealm(contextPath);
}
session.getTransaction().commit();
session.getTransactionManager().commit();
} catch (RuntimeException re) {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().rollback();
}
throw re;
} finally {
@ -180,11 +180,11 @@ public class KeycloakApplication extends Application {
protected void migrateModel() {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
MigrationModelManager.migrate(session);
session.getTransaction().commit();
session.getTransactionManager().commit();
} catch (Exception e) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
logger.migrationFailure(e);
throw e;
} finally {
@ -294,7 +294,7 @@ public class KeycloakApplication extends Application {
KeycloakSession session = sessionFactory.create();
boolean exists = false;
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmManager manager = new RealmManager(session);
@ -313,9 +313,9 @@ public class KeycloakApplication extends Application {
RealmModel realm = manager.importRealm(rep);
logger.importedRealm(realm.getName(), from);
}
session.getTransaction().commit();
session.getTransactionManager().commit();
} catch (Throwable t) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
if (!exists) {
logger.unableToImportRealm(t, rep.getRealm(), from);
}
@ -345,7 +345,7 @@ public class KeycloakApplication extends Application {
for (UserRepresentation userRep : realmRep.getUsers()) {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
RealmModel realm = session.realms().getRealmByName(realmRep.getRealm());
if (realm == null) {
@ -357,13 +357,13 @@ public class KeycloakApplication extends Application {
RepresentationToModel.createRoleMappings(userRep, user, realm);
}
session.getTransaction().commit();
session.getTransactionManager().commit();
logger.addUserSuccess(userRep.getUsername(), realmRep.getRealm());
} catch (ModelDuplicateException e) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
logger.addUserFailedUserExists(userRep.getUsername(), realmRep.getRealm());
} catch (Throwable t) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
logger.addUserFailed(t, userRep.getUsername(), realmRep.getRealm());
} finally {
session.close();

View file

@ -536,7 +536,7 @@ public class AuthenticationManagementResource {
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(rep.getId());
if (model == null) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
throw new NotFoundException("Illegal execution");
}
@ -596,7 +596,7 @@ public class AuthenticationManagementResource {
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
throw new NotFoundException("Illegal execution");
}
@ -642,7 +642,7 @@ public class AuthenticationManagementResource {
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
throw new NotFoundException("Illegal execution");
}
@ -682,7 +682,7 @@ public class AuthenticationManagementResource {
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
throw new NotFoundException("Illegal execution");
}
@ -718,7 +718,7 @@ public class AuthenticationManagementResource {
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) {
session.getTransaction().setRollbackOnly();
session.getTransactionManager().setRollbackOnly();
throw new NotFoundException("Illegal execution");
}

View file

@ -73,8 +73,8 @@ public class ClientInitialAccessResource {
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientInitialAccessModel.getId()).representation(config).success();
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().commit();
}
ClientInitialAccessPresentation rep = wrap(clientInitialAccessModel);

View file

@ -0,0 +1,152 @@
/*
* 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.services.resources.admin;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.common.ClientConnection;
import org.keycloak.component.ComponentModel;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.services.ServicesLogger;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ComponentResource {
protected static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
protected RealmModel realm;
private RealmAuth auth;
private AdminEventBuilder adminEvent;
@Context
protected ClientConnection clientConnection;
@Context
protected UriInfo uriInfo;
@Context
protected KeycloakSession session;
@Context
protected HttpHeaders headers;
public ComponentResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
this.auth = auth;
this.realm = realm;
this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.USER);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent, @QueryParam("type") String type) {
auth.requireManage();
if (parent == null) parent = realm.getId();
List<ComponentModel> components = realm.getComponents(parent, type);
List<ComponentRepresentation> reps = new LinkedList<>();
for (ComponentModel component : components) {
ComponentRepresentation rep = ModelToRepresentation.toRepresentation(component);
reps.add(rep);
}
return reps;
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(ComponentRepresentation rep) {
auth.requireManage();
ComponentModel model = RepresentationToModel.toModel(rep);
if (model.getParentId() == null) model.setParentId(realm.getId());
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
model = realm.addComponentModel(model);
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
}
@GET
@Path("{id}")
public ComponentRepresentation getComponent(@PathParam("id") String id) {
auth.requireManage();
ComponentModel model = realm.getComponent(id);
if (model == null) {
throw new NotFoundException("Could not find component");
}
return ModelToRepresentation.toRepresentation(model);
}
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
public void updateComponent(@PathParam("id") String id, ComponentRepresentation rep) {
auth.requireManage();
ComponentModel model = realm.getComponent(id);
if (model == null) {
throw new NotFoundException("Could not find component");
}
model = RepresentationToModel.toModel(rep);
model.setId(id);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
realm.updateComponent(model);
}
@DELETE
@Path("{id}")
public void removeComponent(@PathParam("id") String id) {
auth.requireManage();
ComponentModel model = realm.getComponent(id);
if (model == null) {
throw new NotFoundException("Could not find component");
}
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo, model.getId()).success();
realm.removeComponent(model);
}
}

View file

@ -321,7 +321,7 @@ public class RealmAdminResource {
*/
@Path("users")
public UsersResource users() {
UsersResource users = new UsersResource(realm, auth, tokenManager, adminEvent);
UsersResource users = new UsersResource(realm, auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(users);
//resourceContext.initResource(users);
return users;

View file

@ -127,7 +127,7 @@ public class UsersResource {
@Context
protected HttpHeaders headers;
public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager, AdminEventBuilder adminEvent) {
public UsersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
this.auth = auth;
this.realm = realm;
this.adminEvent = adminEvent;
@ -172,8 +172,8 @@ public class UsersResource {
updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().commit();
}
return Response.noContent().build();
} catch (ModelDuplicateException e) {
@ -214,19 +214,19 @@ public class UsersResource {
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().commit();
}
return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getId()).build()).build();
} catch (ModelDuplicateException e) {
if (session.getTransaction().isActive()) {
session.getTransaction().setRollbackOnly();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().setRollbackOnly();
}
return ErrorResponse.exists("User exists with same username or email");
} catch (ModelException me){
if (session.getTransaction().isActive()) {
session.getTransaction().setRollbackOnly();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().setRollbackOnly();
}
return ErrorResponse.exists("Could not create user");
}

View file

@ -25,7 +25,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import javax.ws.rs.GET;
import javax.ws.rs.WebApplicationException;
@ -33,12 +32,13 @@ import javax.ws.rs.core.Context;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.events.EventType;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.policy.PasswordPolicyProvider;
import org.keycloak.policy.PasswordPolicyProviderFactory;
import org.keycloak.provider.*;
import org.keycloak.representations.idm.ComponentTypeRepresentation;
import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation;
import org.keycloak.theme.Theme;
import org.keycloak.theme.ThemeProvider;
@ -115,12 +115,26 @@ public class ServerInfoAdminResource {
Map<String, ProviderRepresentation> providers = new HashMap<>();
if (providerIds != null) {
info.setComponentTypes(new HashMap<>());
for (String name : providerIds) {
ProviderRepresentation provider = new ProviderRepresentation();
ProviderFactory<?> pi = session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name);
if (ServerInfoAwareProviderFactory.class.isAssignableFrom(pi.getClass())) {
provider.setOperationalInfo(((ServerInfoAwareProviderFactory) pi).getOperationalInfo());
}
if (pi instanceof ConfiguredProvider) {
ComponentTypeRepresentation rep = new ComponentTypeRepresentation();
rep.setId(pi.getId());
ConfiguredProvider configured = (ConfiguredProvider)pi;
rep.setHelpText(configured.getHelpText());
rep.setProperties(ModelToRepresentation.toRepresentation(configured.getConfigProperties()));
List<ComponentTypeRepresentation> reps = info.getComponentTypes().get(spi.getProviderClass().getName());
if (reps == null) {
reps = new LinkedList<>();
info.getComponentTypes().put(spi.getProviderClass().getName(), reps);
}
reps.add(rep);
}
providers.put(name, provider);
}
}
@ -225,15 +239,7 @@ public class ServerInfoAdminResource {
rep.setCategory(mapper.getDisplayCategory());
rep.setProperties(new LinkedList<ConfigPropertyRepresentation>());
List<ProviderConfigProperty> configProperties = mapper.getConfigProperties();
for (ProviderConfigProperty prop : configProperties) {
ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
propRep.setName(prop.getName());
propRep.setLabel(prop.getLabel());
propRep.setType(prop.getType());
propRep.setDefaultValue(prop.getDefaultValue());
propRep.setHelpText(prop.getHelpText());
rep.getProperties().add(propRep);
}
rep.setProperties(ModelToRepresentation.toRepresentation(configProperties));
types.add(rep);
}
}

View file

@ -41,7 +41,7 @@ public class ClusterAwareScheduledTaskRunner extends ScheduledTaskRunner {
@Override
protected void runTask(final KeycloakSession session) {
session.getTransaction().begin();
session.getTransactionManager().begin();
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
String taskKey = task.getClass().getSimpleName();
@ -56,7 +56,7 @@ public class ClusterAwareScheduledTaskRunner extends ScheduledTaskRunner {
});
session.getTransaction().commit();
session.getTransactionManager().commit();
if (result.isExecuted()) {
logger.debugf("Executed scheduled task %s", taskKey);

View file

@ -45,7 +45,7 @@ public class ScheduledTaskRunner implements Runnable {
} catch (Throwable t) {
logger.failedToRunScheduledTask(t, task.getClass().getSimpleName());
session.getTransaction().rollback();
session.getTransactionManager().rollback();
} finally {
try {
session.close();
@ -56,9 +56,9 @@ public class ScheduledTaskRunner implements Runnable {
}
protected void runTask(KeycloakSession session) {
session.getTransaction().begin();
session.getTransactionManager().begin();
task.run(session);
session.getTransaction().commit();
session.getTransactionManager().commit();
logger.debug("Executed scheduled task " + task.getClass().getSimpleName());
}

View file

@ -39,7 +39,6 @@ import org.keycloak.testsuite.util.cli.TestsuiteCLI;
import org.keycloak.util.JsonSerialization;
import javax.servlet.DispatcherType;
import javax.ws.rs.core.Application;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -249,7 +248,7 @@ public class KeycloakServer {
public void importRealm(RealmRepresentation rep) {
KeycloakSession session = sessionFactory.create();;
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmManager manager = new RealmManager(session);
@ -268,7 +267,7 @@ public class KeycloakServer {
info("Imported realm " + realm.getName());
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}
@ -278,11 +277,11 @@ public class KeycloakServer {
if (System.getProperty("keycloak.createAdminUser", "true").equals("true")) {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
if (new ApplianceBootstrap(session).isNoMasterUser()) {
new ApplianceBootstrap(session).createMasterRealmUser("admin", "admin");
}
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}

View file

@ -265,7 +265,7 @@ public class AdapterTestStrategy extends ExternalResource {
RealmModel realm = session.realms().getRealmByName("demo");
int originalIdle = realm.getSsoSessionIdleTimeout();
realm.setSsoSessionIdleTimeout(1);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(2);
@ -278,7 +278,7 @@ public class AdapterTestStrategy extends ExternalResource {
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("demo");
realm.setSsoSessionIdleTimeout(originalIdle);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(0);
@ -300,7 +300,7 @@ public class AdapterTestStrategy extends ExternalResource {
RealmModel realm = session.realms().getRealmByName("demo");
int originalIdle = realm.getSsoSessionIdleTimeout();
realm.setSsoSessionIdleTimeout(1);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(2);
@ -308,7 +308,7 @@ public class AdapterTestStrategy extends ExternalResource {
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("demo");
session.sessions().removeExpired(realm);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
// test SSO
@ -321,7 +321,7 @@ public class AdapterTestStrategy extends ExternalResource {
UserModel user = session.users().getUserByUsername("bburke@redhat.com", realm);
new ResourceAdminManager(session).logoutUser(null, realm, user, session);
realm.setSsoSessionIdleTimeout(originalIdle);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(0);
@ -343,7 +343,7 @@ public class AdapterTestStrategy extends ExternalResource {
RealmModel realm = session.realms().getRealmByName("demo");
int original = realm.getSsoSessionMaxLifespan();
realm.setSsoSessionMaxLifespan(1);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(2);
@ -356,7 +356,7 @@ public class AdapterTestStrategy extends ExternalResource {
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("demo");
realm.setSsoSessionMaxLifespan(original);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
Time.setOffset(0);

View file

@ -125,7 +125,7 @@ public class CookieTokenStoreAdapterTest {
RealmModel realm = session.realms().getRealmByName("demo");
int originalTokenTimeout = realm.getAccessTokenLifespan();
realm.setAccessTokenLifespan(3);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
// login to customer-cookie-portal
@ -164,7 +164,7 @@ public class CookieTokenStoreAdapterTest {
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("demo");
realm.setAccessTokenLifespan(originalTokenTimeout);
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
} finally {
Time.setOffset(0);

View file

@ -58,7 +58,7 @@ public abstract class AbstractAuthorizationTest {
protected <R> R onAuthorizationSession(Function<AuthorizationProvider, R> function) {
KeycloakSession keycloakSession = startKeycloakSession();
KeycloakTransactionManager transaction = keycloakSession.getTransaction();
KeycloakTransactionManager transaction = keycloakSession.getTransactionManager();
try {
AuthorizationProvider authorizationProvider = keycloakSession.getProvider(AuthorizationProvider.class);
@ -80,7 +80,7 @@ public abstract class AbstractAuthorizationTest {
protected void onAuthorizationSession(Consumer<AuthorizationProvider> consumer) {
KeycloakSession keycloakSession = startKeycloakSession();
KeycloakTransactionManager transaction = keycloakSession.getTransaction();
KeycloakTransactionManager transaction = keycloakSession.getTransactionManager();
try {
AuthorizationProvider authorizationProvider = keycloakSession.getProvider(AuthorizationProvider.class);

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.testsuite.federation.storage;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -23,8 +24,7 @@ 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.UserStorageProvider;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
@ -32,28 +32,33 @@ import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserMapStorage implements UserLookupProvider, StorageProvider, UserCredentialValidatorProvider, UserRegistrationProvider {
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserCredentialValidatorProvider, UserRegistrationProvider {
protected Map<String, String> userPasswords;
protected StorageProviderModel model;
protected ComponentModel model;
protected KeycloakSession session;
public UserMapStorage(KeycloakSession session, StorageProviderModel model, Map<String, String> userPasswords) {
public static final AtomicInteger allocations = new AtomicInteger(0);
public static final AtomicInteger closings = new AtomicInteger(0);
public UserMapStorage(KeycloakSession session, ComponentModel model, Map<String, String> userPasswords) {
this.session = session;
this.model = model;
this.userPasswords = userPasswords;
allocations.incrementAndGet();
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
StorageId storageId = new StorageId(id);
final String username = storageId.getStorageId();
final String username = storageId.getExternalId();
if (!userPasswords.containsKey(username)) return null;
return createUser(realm, username);
@ -94,12 +99,6 @@ public class UserMapStorage implements UserLookupProvider, StorageProvider, User
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, "");
@ -131,11 +130,6 @@ public class UserMapStorage implements UserLookupProvider, StorageProvider, User
}
@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) {
@ -151,6 +145,7 @@ public class UserMapStorage implements UserLookupProvider, StorageProvider, User
@Override
public void close() {
closings.incrementAndGet();
}
}

View file

@ -17,22 +17,19 @@
package org.keycloak.testsuite.federation.storage;
import org.keycloak.Config;
import org.keycloak.component.ComponentModel;
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 org.keycloak.storage.UserStorageProviderFactory;
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 class UserMapStorageFactory implements UserStorageProviderFactory<UserMapStorage> {
public static final String PROVIDER_ID = "user-password-map";
@ -40,7 +37,7 @@ public class UserMapStorageFactory implements StorageProviderFactory<UserMapStor
protected Map<String, String> userPasswords = new Hashtable<>();
@Override
public UserMapStorage getInstance(KeycloakSession session, StorageProviderModel model) {
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
return new UserMapStorage(session, model, userPasswords);
}
@ -49,11 +46,6 @@ public class UserMapStorageFactory implements StorageProviderFactory<UserMapStor
return PROVIDER_ID;
}
@Override
public StorageProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.testsuite.federation.storage;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -23,11 +24,9 @@ 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.UserStorageProvider;
import org.keycloak.storage.adapter.AbstractUserAdapter;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
@ -42,14 +41,14 @@ import java.util.Properties;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserPropertyFileStorage implements UserLookupProvider, StorageProvider, UserCredentialValidatorProvider, UserQueryProvider {
public class UserPropertyFileStorage implements UserLookupProvider, UserStorageProvider, UserCredentialValidatorProvider, UserQueryProvider {
protected Properties userPasswords;
protected StorageProviderModel model;
protected ComponentModel model;
protected KeycloakSession session;
protected boolean federatedStorageEnabled;
public UserPropertyFileStorage(KeycloakSession session, StorageProviderModel model, Properties userPasswords) {
public UserPropertyFileStorage(KeycloakSession session, ComponentModel model, Properties userPasswords) {
this.session = session;
this.model = model;
this.userPasswords = userPasswords;
@ -60,7 +59,7 @@ public class UserPropertyFileStorage implements UserLookupProvider, StorageProvi
@Override
public UserModel getUserById(String id, RealmModel realm) {
StorageId storageId = new StorageId(id);
final String username = storageId.getStorageId();
final String username = storageId.getExternalId();
if (!userPasswords.containsKey(username)) return null;
return createUser(realm, username);
@ -116,11 +115,6 @@ public class UserPropertyFileStorage implements UserLookupProvider, StorageProvi
}
@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) {

View file

@ -17,33 +17,28 @@
package org.keycloak.testsuite.federation.storage;
import org.keycloak.Config;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderFactory;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.UserStorageProviderFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserPropertyFileStorageFactory implements StorageProviderFactory<UserPropertyFileStorage> {
public class UserPropertyFileStorageFactory implements UserStorageProviderFactory<UserPropertyFileStorage> {
public static final String PROVIDER_ID = "user-password-props";
@Override
public UserPropertyFileStorage getInstance(KeycloakSession session, StorageProviderModel model) {
public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
Properties props = new Properties();
try {
props.load(getClass().getResourceAsStream(model.getConfig().get("property.file")));
props.load(getClass().getResourceAsStream(model.getConfig().getFirst("property.file")));
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -55,11 +50,6 @@ public class UserPropertyFileStorageFactory implements StorageProviderFactory<Us
return PROVIDER_ID;
}
@Override
public StorageProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {

View file

@ -21,6 +21,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -30,7 +31,7 @@ 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.storage.UserStorageProviderModel;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginPage;
@ -47,31 +48,35 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserFederationStorageTest {
public static StorageProviderModel memoryProvider = null;
public class UserStorageTest {
public static ComponentModel 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");
UserStorageProviderModel model = new UserStorageProviderModel();
model.setName("memory");
model.setPriority(0);
model.setProviderName(UserMapStorageFactory.PROVIDER_ID);
memoryProvider = appRealm.addStorageProvider(model);
model = new StorageProviderModel();
model.setDisplayName("read-only-user-props");
model.setProviderId(UserMapStorageFactory.PROVIDER_ID);
model.setParentId(appRealm.getId());
memoryProvider = appRealm.addComponentModel(model);
model = new UserStorageProviderModel();
model.setName("read-only-user-props");
model.setPriority(1);
model.setProviderName(UserPropertyFileStorageFactory.PROVIDER_ID);
model.getConfig().put("property.file", "/storage-test/read-only-user-password.properties");
appRealm.addStorageProvider(model);
model = new StorageProviderModel();
model.setDisplayName("user-props");
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
model.setParentId(appRealm.getId());
model.getConfig().putSingle("property.file", "/storage-test/read-only-user-password.properties");
appRealm.addComponentModel(model);
model = new UserStorageProviderModel();
model.setName("user-props");
model.setPriority(2);
model.setProviderName(UserPropertyFileStorageFactory.PROVIDER_ID);
model.getConfig().put("property.file", "/storage-test/user-password.properties");
model.getConfig().put("USER_FEDERATED_STORAGE", "true");
appRealm.addStorageProvider(model);
model.setParentId(appRealm.getId());
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
model.getConfig().putSingle("property.file", "/storage-test/user-password.properties");
model.getConfig().putSingle("USER_FEDERATED_STORAGE", "true");
appRealm.addComponentModel(model);
}
});
@Rule
@ -265,4 +270,27 @@ public class UserFederationStorageTest {
}
@Test
public void testLifecycle() {
UserMapStorage.allocations.set(0);
UserMapStorage.closings.set(0);
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().addUser(realm, "memuser");
Assert.assertNotNull(user);
user = session.users().getUserByUsername("nonexistent", realm);
Assert.assertNull(user);
keycloakRule.stopSession(session, true);
Assert.assertEquals(1, UserMapStorage.allocations.get());
Assert.assertEquals(1, UserMapStorage.closings.get());
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
user = session.users().getUserByUsername("memuser", realm);
session.users().removeUser(realm, user);
Assert.assertNull(session.users().getUserByUsername("memuser", realm));
keycloakRule.stopSession(session, true);
}
}

View file

@ -81,16 +81,16 @@ public class AbstractModelTest {
protected void commit(boolean rollback) {
if (rollback) {
session.getTransaction().rollback();
session.getTransactionManager().rollback();
} else {
session.getTransaction().commit();
session.getTransactionManager().commit();
}
resetSession();
}
protected void resetSession() {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
if (session.getTransactionManager().isActive()) {
session.getTransactionManager().rollback();
}
kc.stopSession(session, false);
session = kc.startSession();

View file

@ -74,7 +74,7 @@ public class AdapterTest extends AbstractModelTest {
realmModel.setAccessTokenLifespan(1000);
realmModel.addDefaultRole("foo");
session.getTransaction().commit();
session.getTransactionManager().commit();
resetSession();
realmModel = realmManager.getRealm(realmModel.getId());

View file

@ -105,7 +105,7 @@ public class CacheTest {
assertNotNull(user2.getLastName());
} finally {
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
}
}
@ -121,7 +121,7 @@ public class CacheTest {
RoleModel fooRole = client.addRole("foo-role");
user.grantRole(fooRole);
} finally {
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
}
@ -136,7 +136,7 @@ public class CacheTest {
ClientModel client = realm.getClientByClientId("foo");
realm.removeClient(client.getId());
} finally {
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
}
@ -152,7 +152,7 @@ public class CacheTest {
Assert.assertEquals(roles.size(), grantedRolesCount - 1);
} finally {
session.getTransaction().commit();
session.getTransactionManager().commit();
session.close();
}
}

View file

@ -35,14 +35,14 @@ public class TransactionsTest {
public void testTransactionActive() {
KeycloakSession session = kc.startSession();
Assert.assertTrue(session.getTransaction().isActive());
session.getTransaction().commit();
Assert.assertFalse(session.getTransaction().isActive());
Assert.assertTrue(session.getTransactionManager().isActive());
session.getTransactionManager().commit();
Assert.assertFalse(session.getTransactionManager().isActive());
session.getTransaction().begin();
Assert.assertTrue(session.getTransaction().isActive());
session.getTransaction().rollback();
Assert.assertFalse(session.getTransaction().isActive());
session.getTransactionManager().begin();
Assert.assertTrue(session.getTransactionManager().isActive());
session.getTransactionManager().rollback();
Assert.assertFalse(session.getTransactionManager().isActive());
session.close();
}

View file

@ -217,7 +217,7 @@ public class UserModelTest extends AbstractModelTest {
UserModel user1 = session.users().addUser(realm, "user1");
commit();
realm = session.realms().getRealmByName("original");
List<UserModel> users = session.users().searchForUser("user", realm, 0, 7);
Assert.assertTrue(users.contains(user1));
}
@ -238,6 +238,7 @@ public class UserModelTest extends AbstractModelTest {
user3.setSingleAttribute("key2", "value21");
commit();
realm = session.realms().getRealmByName("original");
List<UserModel> users = session.users().searchForUserByUserAttribute("key1", "value1", realm);
Assert.assertEquals(2, users.size());
@ -284,6 +285,7 @@ public class UserModelTest extends AbstractModelTest {
// Search and assert service account user not found
realm = realmManager.getRealmByName("original");
client = realm.getClientByClientId("foo");
UserModel searched = session.users().getServiceAccount(client);
Assert.assertEquals(searched, user1);
users = session.users().searchForUser("John Doe", realm);

View file

@ -85,12 +85,12 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
public UserRepresentation getUser(String realm, String name) {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmModel realmByName = session.realms().getRealmByName(realm);
UserModel user = session.users().getUserByUsername(name, realmByName);
UserRepresentation userRep = user != null ? ModelToRepresentation.toRepresentation(user) : null;
session.getTransaction().commit();
session.getTransactionManager().commit();
return userRep;
} finally {
session.close();
@ -99,11 +99,11 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
public UserRepresentation getUserById(String realm, String id) {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmModel realmByName = session.realms().getRealmByName(realm);
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session.users().getUserById(id, realmByName));
session.getTransaction().commit();
session.getTransactionManager().commit();
return userRep;
} finally {
session.close();
@ -112,7 +112,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
protected void setupKeycloak() {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmManager manager = new RealmManager(session);
@ -121,7 +121,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
configure(session, manager, adminstrationRealm);
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}
@ -129,7 +129,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
public void update(KeycloakRule.KeycloakSetup configurer, String realmId) {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmManager manager = new RealmManager(session);
@ -141,7 +141,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
configurer.session = session;
configurer.config(manager, adminstrationRealm, appRealm);
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}
@ -221,7 +221,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
protected void removeTestRealms() {
KeycloakSession session = server.getSessionFactory().create();
try {
session.getTransaction().begin();
session.getTransactionManager().begin();
RealmManager realmManager = new RealmManager(session);
for (String realmName : getTestRealms()) {
RealmModel realm = realmManager.getRealmByName(realmName);
@ -229,7 +229,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
realmManager.removeRealm(realm);
}
}
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}
@ -248,12 +248,12 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
public KeycloakSession startSession() {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
return session;
}
public void stopSession(KeycloakSession session, boolean commit) {
KeycloakTransaction transaction = session.getTransaction();
KeycloakTransaction transaction = session.getTransactionManager();
if (commit && !transaction.getRollbackOnly()) {
transaction.commit();
} else {

View file

@ -58,7 +58,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
public void configure(KeycloakSetup configurer) {
KeycloakSession session = server.getSessionFactory().create();
session.getTransaction().begin();
session.getTransactionManager().begin();
try {
RealmManager manager = new RealmManager(session);
@ -70,7 +70,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
configurer.session = session;
configurer.config(manager, adminstrationRealm, appRealm);
session.getTransaction().commit();
session.getTransactionManager().commit();
} finally {
session.close();
}