[KEYCLOAK-8285] Remove user-storage-jpa and user-storage-simple from Keycloak repository
This commit is contained in:
parent
01051016f5
commit
8b6db21e56
20 changed files with 0 additions and 1561 deletions
|
@ -36,7 +36,5 @@
|
||||||
<module>authenticator</module>
|
<module>authenticator</module>
|
||||||
<module>rest</module>
|
<module>rest</module>
|
||||||
<module>domain-extension</module>
|
<module>domain-extension</module>
|
||||||
<module>user-storage-simple</module>
|
|
||||||
<module>user-storage-jpa</module>
|
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
Example User Storage Provider with EJB and JPA
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
This is an example of the User Storage SPI implemented using EJB and JPA. You must first deploy the datasource it uses.
|
|
||||||
Start up the Keycloak server. Then in the directory of this example type the following maven command:
|
|
||||||
|
|
||||||
mvn -Padd-datasource install
|
|
||||||
|
|
||||||
You only need to execute this maven command once. If you execute this again, then you will get an error message that the datasource
|
|
||||||
already exists.
|
|
||||||
|
|
||||||
If you open the pom.xml file you'll see that the add-datasource profile creates an XA datasource using the built
|
|
||||||
in H2 database that comes with the server. An XA datasource is required because you cannot use two non-xa datasources
|
|
||||||
in the same transaction. The Keycloak database is non-xa.
|
|
||||||
|
|
||||||
Another thing to note is that the xa-datasource created is in-memory only. If you reboot the server, any users you've
|
|
||||||
added or changes you've made to users loaded by this provider will be wiped clean.
|
|
||||||
|
|
||||||
To deploy the provider, run the following maven command:
|
|
||||||
|
|
||||||
mvn clean install wildfly:deploy
|
|
||||||
|
|
||||||
You can run as many times as you want and the provider will be redeployed.
|
|
||||||
|
|
||||||
Login and go to the User Federation tab and you should now see your deployed provider in the add-provider list box.
|
|
||||||
Add the provider, save it, then any new user you create will be stored and in the custom store you implemented. You
|
|
||||||
can modify the example and hot deploy it using the above maven command again.
|
|
||||||
|
|
|
@ -1,141 +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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-examples-providers-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>4.5.0.Final-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<name>User Storage JPA Provider Example</name>
|
|
||||||
<description/>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>user-storage-jpa-example</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-core</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-server-spi</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.logging</groupId>
|
|
||||||
<artifactId>jboss-logging</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
|
||||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-entitymanager</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.spec.javax.ejb</groupId>
|
|
||||||
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
|
|
||||||
<version>1.0.0.Final</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>user-storage-jpa-example</finalName>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.wildfly.plugins</groupId>
|
|
||||||
<artifactId>wildfly-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skip>false</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<profiles>
|
|
||||||
<!-- this profile deploys an XA H2 datasource connection. It is in-memory only, so rebooting the server will lose
|
|
||||||
your changes. Run type: mvn -Padd-datasource install. THis can only be run once. If you run it again
|
|
||||||
you'll get an error that the datasource already exists -->
|
|
||||||
<profile>
|
|
||||||
<id>add-datasource</id>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.wildfly.plugins</groupId>
|
|
||||||
<artifactId>wildfly-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skip>false</skip>
|
|
||||||
<force>true</force>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>add-datasource</id>
|
|
||||||
<phase>install</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>add-resource</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<force/>
|
|
||||||
<address>subsystem=datasources</address>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<address>xa-data-source=java:jboss/datasources/ExampleXADS</address>
|
|
||||||
<properties>
|
|
||||||
<jndi-name>java:jboss/datasources/ExampleXADS</jndi-name>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
<driver-name>h2</driver-name>
|
|
||||||
</properties>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<address>
|
|
||||||
xa-datasource-properties=URL
|
|
||||||
</address>
|
|
||||||
<properties>
|
|
||||||
<value>jdbc:h2:mem:test</value>
|
|
||||||
</properties>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,316 +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.examples.storage.user;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.credential.CredentialInput;
|
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
|
||||||
import org.keycloak.models.cache.OnUserCache;
|
|
||||||
import org.keycloak.storage.StorageId;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
|
||||||
import org.keycloak.storage.user.UserQueryProvider;
|
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
|
||||||
|
|
||||||
import javax.ejb.Local;
|
|
||||||
import javax.ejb.Remove;
|
|
||||||
import javax.ejb.Stateful;
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import javax.persistence.PersistenceContext;
|
|
||||||
import javax.persistence.TypedQuery;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
@Stateful
|
|
||||||
@Local(EjbExampleUserStorageProvider.class)
|
|
||||||
public class EjbExampleUserStorageProvider implements UserStorageProvider,
|
|
||||||
UserLookupProvider,
|
|
||||||
UserRegistrationProvider,
|
|
||||||
UserQueryProvider,
|
|
||||||
CredentialInputUpdater,
|
|
||||||
CredentialInputValidator,
|
|
||||||
OnUserCache
|
|
||||||
{
|
|
||||||
private static final Logger logger = Logger.getLogger(EjbExampleUserStorageProvider.class);
|
|
||||||
public static final String PASSWORD_CACHE_KEY = UserAdapter.class.getName() + ".password";
|
|
||||||
|
|
||||||
@PersistenceContext
|
|
||||||
protected EntityManager em;
|
|
||||||
|
|
||||||
protected ComponentModel model;
|
|
||||||
protected KeycloakSession session;
|
|
||||||
|
|
||||||
public void setModel(ComponentModel model) {
|
|
||||||
this.model = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSession(KeycloakSession session) {
|
|
||||||
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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remove
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserById(String id, RealmModel realm) {
|
|
||||||
logger.info("getUserById: " + id);
|
|
||||||
String persistenceId = StorageId.externalId(id);
|
|
||||||
UserEntity entity = em.find(UserEntity.class, persistenceId);
|
|
||||||
if (entity == null) {
|
|
||||||
logger.info("could not find user by id: " + id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new UserAdapter(session, realm, model, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
|
||||||
logger.info("getUserByUsername: " + username);
|
|
||||||
TypedQuery<UserEntity> query = em.createNamedQuery("getUserByUsername", UserEntity.class);
|
|
||||||
query.setParameter("username", username);
|
|
||||||
List<UserEntity> result = query.getResultList();
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
logger.info("could not find username: " + username);
|
|
||||||
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(UUID.randomUUID().toString());
|
|
||||||
entity.setUsername(username);
|
|
||||||
em.persist(entity);
|
|
||||||
logger.info("added user: " + username);
|
|
||||||
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 onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
|
|
||||||
String password = ((UserAdapter)delegate).getPassword();
|
|
||||||
if (password != null) {
|
|
||||||
user.getCachedWith().put(PASSWORD_CACHE_KEY, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsCredentialType(String credentialType) {
|
|
||||||
return CredentialModel.PASSWORD.equals(credentialType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;
|
|
||||||
UserCredentialModel cred = (UserCredentialModel)input;
|
|
||||||
UserAdapter adapter = getUserAdapter(user);
|
|
||||||
adapter.setPassword(cred.getValue());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAdapter getUserAdapter(UserModel user) {
|
|
||||||
UserAdapter adapter = null;
|
|
||||||
if (user instanceof CachedUserModel) {
|
|
||||||
adapter = (UserAdapter)((CachedUserModel)user).getDelegateForUpdate();
|
|
||||||
} else {
|
|
||||||
adapter = (UserAdapter)user;
|
|
||||||
}
|
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
if (!supportsCredentialType(credentialType)) return;
|
|
||||||
|
|
||||||
getUserAdapter(user).setPassword(null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
|
||||||
if (getUserAdapter(user).getPassword() != null) {
|
|
||||||
Set<String> set = new HashSet<>();
|
|
||||||
set.add(CredentialModel.PASSWORD);
|
|
||||||
return set;
|
|
||||||
} else {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
return supportsCredentialType(credentialType) && getPassword(user) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;
|
|
||||||
UserCredentialModel cred = (UserCredentialModel)input;
|
|
||||||
String password = getPassword(user);
|
|
||||||
return password != null && password.equals(cred.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword(UserModel user) {
|
|
||||||
String password = null;
|
|
||||||
if (user instanceof CachedUserModel) {
|
|
||||||
password = (String)((CachedUserModel)user).getCachedWith().get(PASSWORD_CACHE_KEY);
|
|
||||||
} else if (user instanceof UserAdapter) {
|
|
||||||
password = ((UserAdapter)user).getPassword();
|
|
||||||
}
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getUsersCount(RealmModel realm) {
|
|
||||||
Object count = em.createNamedQuery("getUserCount")
|
|
||||||
.getSingleResult();
|
|
||||||
return ((Number)count).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getUsers(RealmModel realm) {
|
|
||||||
return getUsers(realm, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
|
|
||||||
TypedQuery<UserEntity> query = em.createNamedQuery("getAllUsers", UserEntity.class);
|
|
||||||
if (firstResult != -1) {
|
|
||||||
query.setFirstResult(firstResult);
|
|
||||||
}
|
|
||||||
if (maxResults != -1) {
|
|
||||||
query.setMaxResults(maxResults);
|
|
||||||
}
|
|
||||||
List<UserEntity> results = query.getResultList();
|
|
||||||
List<UserModel> users = new LinkedList<>();
|
|
||||||
for (UserEntity entity : results) users.add(new UserAdapter(session, realm, model, entity));
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
|
||||||
return searchForUser(search, realm, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
TypedQuery<UserEntity> query = em.createNamedQuery("searchForUser", UserEntity.class);
|
|
||||||
query.setParameter("search", "%" + search.toLowerCase() + "%");
|
|
||||||
if (firstResult != -1) {
|
|
||||||
query.setFirstResult(firstResult);
|
|
||||||
}
|
|
||||||
if (maxResults != -1) {
|
|
||||||
query.setMaxResults(maxResults);
|
|
||||||
}
|
|
||||||
List<UserEntity> results = query.getResultList();
|
|
||||||
List<UserModel> users = new LinkedList<>();
|
|
||||||
for (UserEntity entity : results) users.add(new UserAdapter(session, realm, model, entity));
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +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.examples.storage.user;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
|
||||||
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class EjbExampleUserStorageProviderFactory implements UserStorageProviderFactory<EjbExampleUserStorageProvider> {
|
|
||||||
private static final Logger logger = Logger.getLogger(EjbExampleUserStorageProviderFactory.class);
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EjbExampleUserStorageProvider create(KeycloakSession session, ComponentModel model) {
|
|
||||||
try {
|
|
||||||
InitialContext ctx = new InitialContext();
|
|
||||||
EjbExampleUserStorageProvider provider = (EjbExampleUserStorageProvider)ctx.lookup("java:global/user-storage-jpa-example/" + EjbExampleUserStorageProvider.class.getSimpleName());
|
|
||||||
provider.setModel(model);
|
|
||||||
provider.setSession(session);
|
|
||||||
return provider;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "example-user-storage-jpa";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHelpText() {
|
|
||||||
return "JPA Example User Storage Provider";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
logger.info("<<<<<< Closing factory");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +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.examples.storage.user;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
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 {
|
|
||||||
private static final Logger logger = Logger.getLogger(UserAdapter.class);
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return entity.getPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
entity.setPassword(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +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.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"),
|
|
||||||
@NamedQuery(name="getUserCount", query="select count(u) from UserEntity u"),
|
|
||||||
@NamedQuery(name="getAllUsers", query="select u from UserEntity u"),
|
|
||||||
@NamedQuery(name="searchForUser", query="select u from UserEntity u where " +
|
|
||||||
"( lower(u.username) like :search or u.email like :search ) order by u.username"),
|
|
||||||
})
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?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="user-storage-jpa-example" transaction-type="JTA">
|
|
||||||
<jta-data-source>java:jboss/datasources/ExampleXADS</jta-data-source>
|
|
||||||
|
|
||||||
<class>org.keycloak.examples.storage.user.UserEntity</class>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<property name="hibernate.hbm2ddl.auto" value="update" />
|
|
||||||
<property name="hibernate.show_sql" value="false" />
|
|
||||||
</properties>
|
|
||||||
</persistence-unit>
|
|
||||||
</persistence>
|
|
|
@ -1 +0,0 @@
|
||||||
org.keycloak.examples.storage.user.EjbExampleUserStorageProviderFactory
|
|
|
@ -1,16 +0,0 @@
|
||||||
Example User Storage Provider
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
This is an example of user storage backed by a simple properties file. This properties file only contains username/password
|
|
||||||
key pairs. To deploy this provider you must have Keycloak running in standalone or standalone-ha mode. Then type the follow maven command:
|
|
||||||
|
|
||||||
mvn clean install wildfly:deploy
|
|
||||||
|
|
||||||
|
|
||||||
The "readonly-property-file" provider is hardcoded to look within the users.properties file embeded in the deployment jar
|
|
||||||
THere is one user 'tbrady' with a password of 'superbowl'
|
|
||||||
|
|
||||||
The "writeable-property-file" provider can be configured to point to a property file on disk. It uses federated
|
|
||||||
storage to augment the property file with any other information the user wants.
|
|
||||||
|
|
||||||
Our developer guide walks through the implementation of both of these providers.
|
|
|
@ -1,95 +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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-examples-providers-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>4.5.0.Final-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<name>UserStorageProvider Simple Example</name>
|
|
||||||
<description/>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>user-storage-properties-example</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-core</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-server-spi</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.logging</groupId>
|
|
||||||
<artifactId>jboss-logging</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>user-storage-properties-example</finalName>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.wildfly.plugins</groupId>
|
|
||||||
<artifactId>wildfly-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skip>false</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>product</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>product</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<!-- The example needs to be deployed during the product build, because it's testsuite's dependency.
|
|
||||||
We need to override setting from parent module. -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skip>false</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
|
|
@ -1,147 +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.examples.userstorage.readonly;
|
|
||||||
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.credential.CredentialInput;
|
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.storage.ReadOnlyException;
|
|
||||||
import org.keycloak.storage.StorageId;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.adapter.AbstractUserAdapter;
|
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
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 PropertyFileUserStorageProvider implements
|
|
||||||
UserStorageProvider,
|
|
||||||
UserLookupProvider,
|
|
||||||
CredentialInputValidator,
|
|
||||||
CredentialInputUpdater
|
|
||||||
{
|
|
||||||
protected KeycloakSession session;
|
|
||||||
protected Properties properties;
|
|
||||||
protected ComponentModel model;
|
|
||||||
// map of loaded users in this transaction
|
|
||||||
protected Map<String, UserModel> loadedUsers = new HashMap<>();
|
|
||||||
|
|
||||||
public PropertyFileUserStorageProvider(KeycloakSession session, ComponentModel model, Properties properties) {
|
|
||||||
this.session = session;
|
|
||||||
this.model = model;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserLookupProvider methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
|
||||||
UserModel adapter = loadedUsers.get(username);
|
|
||||||
if (adapter == null) {
|
|
||||||
String password = properties.getProperty(username);
|
|
||||||
if (password != null) {
|
|
||||||
adapter = createAdapter(realm, username);
|
|
||||||
loadedUsers.put(username, adapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserModel createAdapter(RealmModel realm, String username) {
|
|
||||||
return new AbstractUserAdapter(session, realm, model) {
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserById(String id, RealmModel realm) {
|
|
||||||
StorageId storageId = new StorageId(id);
|
|
||||||
String username = storageId.getExternalId();
|
|
||||||
return getUserByUsername(username, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByEmail(String email, RealmModel realm) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// CredentialInputValidator methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
String password = properties.getProperty(user.getUsername());
|
|
||||||
return credentialType.equals(CredentialModel.PASSWORD) && password != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsCredentialType(String credentialType) {
|
|
||||||
return credentialType.equals(CredentialModel.PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;
|
|
||||||
|
|
||||||
UserCredentialModel cred = (UserCredentialModel)input;
|
|
||||||
String password = properties.getProperty(user.getUsername());
|
|
||||||
if (password == null) return false;
|
|
||||||
return password.equals(cred.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialInputUpdater methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (input.getType().equals(CredentialModel.PASSWORD)) throw new ReadOnlyException("user is read only for this update");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
|
||||||
return Collections.EMPTY_SET;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +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.examples.userstorage.readonly;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class PropertyFileUserStorageProviderFactory implements UserStorageProviderFactory<PropertyFileUserStorageProvider> {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(PropertyFileUserStorageProviderFactory.class);
|
|
||||||
|
|
||||||
public static final String PROVIDER_NAME = "readonly-property-file";
|
|
||||||
|
|
||||||
protected Properties properties = new Properties();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return PROVIDER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config.Scope config) {
|
|
||||||
InputStream is = getClass().getClassLoader().getResourceAsStream("/users.properties");
|
|
||||||
|
|
||||||
if (is == null) {
|
|
||||||
logger.warn("Could not find users.properties in classpath");
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
properties.load(is);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.error("Failed to load users.properties file", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyFileUserStorageProvider create(KeycloakSession session, ComponentModel model) {
|
|
||||||
return new PropertyFileUserStorageProvider(session, model, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,313 +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.examples.userstorage.writeable;
|
|
||||||
|
|
||||||
import org.keycloak.common.util.EnvUtil;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.credential.CredentialInput;
|
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.storage.StorageId;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
|
||||||
import org.keycloak.storage.user.UserQueryProvider;
|
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
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 PropertyFileUserStorageProvider implements
|
|
||||||
UserStorageProvider,
|
|
||||||
UserLookupProvider,
|
|
||||||
CredentialInputValidator,
|
|
||||||
CredentialInputUpdater,
|
|
||||||
UserRegistrationProvider,
|
|
||||||
UserQueryProvider {
|
|
||||||
|
|
||||||
|
|
||||||
public static final String UNSET_PASSWORD="#$!-UNSET-PASSWORD";
|
|
||||||
|
|
||||||
protected KeycloakSession session;
|
|
||||||
protected Properties properties;
|
|
||||||
protected ComponentModel model;
|
|
||||||
// map of loaded users in this transaction
|
|
||||||
protected Map<String, UserModel> loadedUsers = new HashMap<>();
|
|
||||||
|
|
||||||
public PropertyFileUserStorageProvider(KeycloakSession session, ComponentModel model, Properties properties) {
|
|
||||||
this.session = session;
|
|
||||||
this.model = model;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserLookupProvider methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
|
||||||
UserModel adapter = loadedUsers.get(username);
|
|
||||||
if (adapter == null) {
|
|
||||||
String password = properties.getProperty(username);
|
|
||||||
if (password != null) {
|
|
||||||
adapter = createAdapter(realm, username);
|
|
||||||
loadedUsers.put(username, adapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserModel createAdapter(RealmModel realm, String username) {
|
|
||||||
return new AbstractUserAdapterFederatedStorage(session, realm, model) {
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUsername(String username) {
|
|
||||||
String pw = (String)properties.remove(username);
|
|
||||||
if (pw != null) {
|
|
||||||
properties.put(username, pw);
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserById(String id, RealmModel realm) {
|
|
||||||
StorageId storageId = new StorageId(id);
|
|
||||||
String username = storageId.getExternalId();
|
|
||||||
return getUserByUsername(username, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel getUserByEmail(String email, RealmModel realm) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserQueryProvider methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getUsersCount(RealmModel realm) {
|
|
||||||
return properties.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getUsers(RealmModel realm) {
|
|
||||||
return getUsers(realm, 0, Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
List<UserModel> users = new LinkedList<>();
|
|
||||||
int i = 0;
|
|
||||||
for (Object obj : properties.keySet()) {
|
|
||||||
if (i++ < firstResult) continue;
|
|
||||||
String username = (String)obj;
|
|
||||||
UserModel user = getUserByUsername(username, realm);
|
|
||||||
users.add(user);
|
|
||||||
if (users.size() >= maxResults) break;
|
|
||||||
}
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserQueryProvider method implementations
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
|
||||||
return searchForUser(search, realm, 0, Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
List<UserModel> users = new LinkedList<>();
|
|
||||||
int i = 0;
|
|
||||||
for (Object obj : properties.keySet()) {
|
|
||||||
String username = (String)obj;
|
|
||||||
if (!username.contains(search)) continue;
|
|
||||||
if (i++ < firstResult) continue;
|
|
||||||
UserModel user = getUserByUsername(username, realm);
|
|
||||||
users.add(user);
|
|
||||||
if (users.size() >= maxResults) break;
|
|
||||||
}
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
|
|
||||||
return searchForUser(params, realm, 0, Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
|
||||||
// only support searching by username
|
|
||||||
String usernameSearchString = params.get("username");
|
|
||||||
if (usernameSearchString == null) return Collections.EMPTY_LIST;
|
|
||||||
return searchForUser(usernameSearchString, realm, firstResult, maxResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
|
||||||
// runtime automatically handles querying UserFederatedStorage
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
|
||||||
// runtime automatically handles querying UserFederatedStorage
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
|
||||||
// Not supported in federated storage
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) {
|
|
||||||
// Not supported in federated storage
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
|
|
||||||
// runtime automatically handles querying UserFederatedStorage
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// UserRegistrationProvider method implementations
|
|
||||||
|
|
||||||
public void save() {
|
|
||||||
String path = model.getConfig().getFirst("path");
|
|
||||||
path = EnvUtil.replace(path);
|
|
||||||
try {
|
|
||||||
FileOutputStream fos = new FileOutputStream(path);
|
|
||||||
properties.store(fos, "");
|
|
||||||
fos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserModel addUser(RealmModel realm, String username) {
|
|
||||||
synchronized (properties) {
|
|
||||||
properties.setProperty(username, UNSET_PASSWORD);
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
return createAdapter(realm, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
|
||||||
synchronized (properties) {
|
|
||||||
if (properties.remove(user.getUsername()) == null) return false;
|
|
||||||
save();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// CredentialInputValidator methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
String password = properties.getProperty(user.getUsername());
|
|
||||||
return credentialType.equals(CredentialModel.PASSWORD) && password != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsCredentialType(String credentialType) {
|
|
||||||
return credentialType.equals(CredentialModel.PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;
|
|
||||||
|
|
||||||
UserCredentialModel cred = (UserCredentialModel)input;
|
|
||||||
String password = properties.getProperty(user.getUsername());
|
|
||||||
if (password == null || UNSET_PASSWORD.equals(password)) return false;
|
|
||||||
return password.equals(cred.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialInputUpdater methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
|
||||||
if (!(input instanceof UserCredentialModel)) return false;
|
|
||||||
if (!input.getType().equals(CredentialModel.PASSWORD)) return false;
|
|
||||||
UserCredentialModel cred = (UserCredentialModel)input;
|
|
||||||
synchronized (properties) {
|
|
||||||
properties.setProperty(user.getUsername(), cred.getValue());
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
|
||||||
if (!credentialType.equals(CredentialModel.PASSWORD)) return;
|
|
||||||
synchronized (properties) {
|
|
||||||
properties.setProperty(user.getUsername(), UNSET_PASSWORD);
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Set<String> disableableTypes = new HashSet<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
disableableTypes.add(CredentialModel.PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
|
||||||
|
|
||||||
return disableableTypes;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +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.examples.userstorage.writeable;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.common.util.EnvUtil;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.component.ComponentValidationException;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
|
||||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class PropertyFileUserStorageProviderFactory implements UserStorageProviderFactory<PropertyFileUserStorageProvider> {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(PropertyFileUserStorageProviderFactory.class);
|
|
||||||
|
|
||||||
public static final String PROVIDER_NAME = "writeable-property-file";
|
|
||||||
|
|
||||||
protected static final List<ProviderConfigProperty> configMetadata;
|
|
||||||
|
|
||||||
static {
|
|
||||||
configMetadata = ProviderConfigurationBuilder.create()
|
|
||||||
.property().name("path")
|
|
||||||
.type(ProviderConfigProperty.STRING_TYPE)
|
|
||||||
.label("Path")
|
|
||||||
.defaultValue("${jboss.server.config.dir}/example-users.properties")
|
|
||||||
.helpText("File path to properties file")
|
|
||||||
.add().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
|
||||||
return configMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
|
|
||||||
String fp = config.getConfig().getFirst("path");
|
|
||||||
if (fp == null) throw new ComponentValidationException("user property file does not exist");
|
|
||||||
fp = EnvUtil.replace(fp);
|
|
||||||
File file = new File(fp);
|
|
||||||
if (!file.exists()) {
|
|
||||||
throw new ComponentValidationException("user property file does not exist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return PROVIDER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyFileUserStorageProvider create(KeycloakSession session, ComponentModel model) {
|
|
||||||
String path = model.getConfig().getFirst("path");
|
|
||||||
path = EnvUtil.replace(path);
|
|
||||||
|
|
||||||
Properties props = new Properties();
|
|
||||||
try {
|
|
||||||
InputStream is = new FileInputStream(path);
|
|
||||||
props.load(is);
|
|
||||||
is.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PropertyFileUserStorageProvider(session, model, props);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
org.keycloak.examples.userstorage.readonly.PropertyFileUserStorageProviderFactory
|
|
||||||
org.keycloak.examples.userstorage.writeable.PropertyFileUserStorageProviderFactory
|
|
|
@ -1,18 +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.
|
|
||||||
#
|
|
||||||
|
|
||||||
tbrady=superbowl
|
|
5
pom.xml
5
pom.xml
|
@ -1399,11 +1399,6 @@
|
||||||
<classifier>classes</classifier>
|
<classifier>classes</classifier>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>user-storage-properties-example</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak.example.demo</groupId>
|
<groupId>org.keycloak.example.demo</groupId>
|
||||||
<artifactId>cxf-jaxws-example</artifactId>
|
<artifactId>cxf-jaxws-example</artifactId>
|
||||||
|
|
|
@ -158,10 +158,6 @@
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
|
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>user-storage-properties-example</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-testsuite-utils</artifactId>
|
<artifactId>keycloak-testsuite-utils</artifactId>
|
||||||
|
|
|
@ -171,11 +171,6 @@
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
|
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>user-storage-properties-example</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Dependency on services from integration-arquillian -->
|
<!-- Dependency on services from integration-arquillian -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak.testsuite</groupId>
|
<groupId>org.keycloak.testsuite</groupId>
|
||||||
|
|
Loading…
Reference in a new issue