Keycloak javax.ejb.EJBTransactionRolledbackException:用于KeyClope用户spi提供程序
下面是我的pom.xmlKeycloak javax.ejb.EJBTransactionRolledbackException:用于KeyClope用户spi提供程序,keycloak,Keycloak,下面是我的pom.xml <properties> <keycloak.version>4.3.0.Final</keycloak.version> <version.hibernate.javax.persistence>1.0.0.Final</version.hibernate.javax.persistence> <version.jboss-ejb-api>1.0.0.Final</v
<properties>
<keycloak.version>4.3.0.Final</keycloak.version>
<version.hibernate.javax.persistence>1.0.0.Final</version.hibernate.javax.persistence>
<version.jboss-ejb-api>1.0.0.Final</version.jboss-ejb-api>
</properties>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>${version.hibernate.javax.persistence}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<version>${version.jboss-ejb-api}</version>
<scope>provided</scope>
</dependency>
</dependencies>
package com.neemiya.keydape.userstoragespi;
导入java.util.UUID;
导入javax.ejb.Local;
导入javax.ejb.Stateful;
导入javax.persistence.EntityManager;
导入javax.persistence.PersistenceContext;
导入javax.persistence.TypedQuery;
导入org.jboss.logging.Logger;
导入org.keydape.component.ComponentModel;
导入org.keydeport.credential.CredentialInput;
导入org.keydepot.credential.CredentialInputValidator;
导入org.keydeport.credential.CredentialModel;
导入org.keydepot.models.keydeposition;
导入org.keydape.models.realmodel;
导入org.keydepate.models.UserCredentialModel;
导入org.keydape.models.UserModel;
导入org.keydepate.models.cache.CachedUserModel;
导入org.keydape.models.cache.OnUserCache;
导入org.keydape.storage.StorageId;
导入org.keydepot.storage.UserStorageProvider;
导入org.keydape.storage.user.UserLookupProvider;
导入com.neemiya.keydape.userstoragespi.entity.UserAccountMapping;
导入com.neemiya.keydape.userstoragespi.entity.UserCredentialEntity;
导入com.neemiya.keydape.userstoragespi.entity.UserEntity;
导入com.neemiya.keydape.userstoragespi.utils.Crypto;
@有状态(钝化能力=假)
@本地(NeemiyaUsersProvider.class)
公共类NeemiyaUsersProvider
实现UserStorageProvider、UserLookupProvider、CredentialInputValidator、OnUserCache{
私有静态最终记录器Logger=Logger.getLogger(NeemiyaUsersProvider.class);
公共静态最终字符串密码\u缓存\u密钥=UserAdapter.class.getName()+“.PASSWORD”;
私有静态最终字符串GET_USER_FOR_USERNAME=“从UserCredentialEntity uc中选择uc,其中uc.USERNAME=:USERNAME”;
私有静态最终字符串GET\u USER\u ACCOUNT\u MAPPING\u FOR\u OWNER=“从UserAccountMapping uam中选择uam,其中uam.userId=:userId和”
+“uam.requestedByUserId=:userId和uam.role=com.neemiya.keydape.userstoragespi.enums.role.owner和”
+“uam.request_status=com.neemiya.keydape.userstoragespi.enums.request_status.completed”;
@持久上下文
受保护的实体管理器em;
受保护组件模型;
受保护密钥会话;
公共void集合模型(组件模型){
this.model=模型;
}
公共无效设置会话(keydeposition会话){
this.session=会话;
}
@凌驾
公众假期结束(){
}
@凌驾
公共UserModel getUserById(字符串id,RealmModel域){
logger.info(“getUserById:+id”);
试一试{
字符串persistenceId=StorageId.externalId(id);
UUID persistenceUUID=UUID.fromString(persistenceId);
UserCredentialEntity-credentialEntity=em.find(UserCredentialEntity.class,persistenceUUID);
if(credentialEntity==null){
logger.info(“无法通过id找到用户:“+id”);
返回null;
}
TypedQuery uamQuery=em.createQuery(为所有者获取用户帐户映射),
UserAccountMapping.class);
setParameter(“userId”,credentialEntity.getUserEntity().getUserId());
UserAccountMapping uam=uamQuery.getSingleResult();
credentialEntity.setAccountId(uam.getAccountId());
返回新的UserAdapter(会话、领域、模型、证书);
}捕获(例外e){
错误(“无法通过id获取用户”+e.getMessage());
}
返回null;
}
@凌驾
公共用户模型getUserByUsername(字符串用户名,RealmModel域){
logger.info(“getUserByUsername:+username”);
试一试{
TypedQuery query=em.createQuery(获取用户的用户名,UserCredentialEntity.class);
query.setParameter(“用户名”,用户名);
UserCredentialEntity credentialEntity=query.getSingleResult();
if(credentialEntity==null){
logger.error(“找不到用户名:“+username”);
返回null;
}
UserEntity=credentialEntity.getUserEntity();
if(实体==null){
logger.error(“无法获取给定用户名的用户”);
返回null;
}
TypedQuery uamQuery=em.createQuery(为所有者获取用户帐户映射),
UserAccountMapping.class);
setParameter(“userId”,entity.getUserId());
UserAccountMapping uam=uamQuery.getSingleResult();
如果(uam==null){
错误(“找不到此用户的所有者映射”);
返回null;
}
credentialEntity.setAccountId(uam.getAccountId());
logger.info(“获取USerCredentialEntity::”+credentialEntity.toString());
返回新的UserAdapter(会话、领域、模型、证书);
}捕获(例外e){
logger.error(“无法验证用户凭据”+e.getMessage());
}
返回null;
}
@凌驾
公共用户模型getUserByEmail(字符串电子邮件,RealmModel域){
返回null;
}
@凌驾
public void onCache(RealmModel领域、CachedUserModel用户、UserModel委托){
字符串密码=((UserAdapter)委托).getPassword();
if(密码!=null){
user.getCachedWith().put(密码\缓存\密钥,密码);
}
}
@凌驾
公共布尔支持credentialType(字符串凭据类型){
返回CredentialModel.PASSWORD.equals(credentialType);
}
@凌驾
公共布尔值isConfiguredFor(RealmModel领域、UserModel用户、字符串凭据类型){
返回supportsCredentialType(credentialType)和&getPassword(user)!=null;
}
@凌驾
公共布尔值有效(RealmModel领域、UserModel用户、CredentialInput输入){
如果(!支持
2018-09-08 16:36:12,303 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-4) SQL Error: 0, SQLState: null
2018-09-08 16:36:12,304 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-4) IJ031070: Transaction cannot proceed: STATUS_MARKED_ROLLBACK
2018-09-08 16:36:12,313 ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation failed on component NeemiyaUsersProvider for method public org.keycloak.models.UserModel com.neemiya.keycloak.userstoragespi.NeemiyaUsersProvider.getUserByUsername(java.lang.String,org.keycloak.models.RealmModel): javax.ejb.EJBTransactionRolledbackException: org.hibernate.exception.GenericJDBCException: could not prepare statement
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:160)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:257)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:334)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:240)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statement
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:492)
at com.neemiya.keycloak.userstoragespi.NeemiyaUsersProvider.getUserByUsername(NeemiyaUsersProvider.java:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
package com.neemiya.keycloak.userstoragespi;
import java.util.UUID;
import javax.ejb.Local;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel;
import org.keycloak.credential.CredentialInput;
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.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 com.neemiya.keycloak.userstoragespi.entity.UserAccountMapping;
import com.neemiya.keycloak.userstoragespi.entity.UserCredentialEntity;
import com.neemiya.keycloak.userstoragespi.entity.UserEntity;
import com.neemiya.keycloak.userstoragespi.utils.Crypto;
@Stateful(passivationCapable = false)
@Local(NeemiyaUsersProvider.class)
public class NeemiyaUsersProvider
implements UserStorageProvider, UserLookupProvider, CredentialInputValidator, OnUserCache {
private static final Logger logger = Logger.getLogger(NeemiyaUsersProvider.class);
public static final String PASSWORD_CACHE_KEY = UserAdapter.class.getName() + ".password";
private static final String GET_USER_FOR_USERNAME = "select uc from UserCredentialEntity uc where uc.username=:username";
private static final String GET_USER_ACCOUNT_MAPPING_FOR_OWNER = "select uam from UserAccountMapping uam where uam.userId = :userId and"
+ " uam.requestedByUserId =:userId and uam.role = com.neemiya.keycloak.userstoragespi.enums.ROLE.owner and "
+ " uam.request_status = com.neemiya.keycloak.userstoragespi.enums.REQUEST_STATUS.completed";
@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 close() {
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
logger.info("getUserById: " + id);
try {
String persistenceId = StorageId.externalId(id);
UUID persistenceUUID = UUID.fromString(persistenceId);
UserCredentialEntity credentialEntity = em.find(UserCredentialEntity.class, persistenceUUID);
if (credentialEntity == null) {
logger.info("could not find user by id: " + id);
return null;
}
TypedQuery<UserAccountMapping> uamQuery = em.createQuery(GET_USER_ACCOUNT_MAPPING_FOR_OWNER,
UserAccountMapping.class);
uamQuery.setParameter("userId", credentialEntity.getUserEntity().getUserId());
UserAccountMapping uam = uamQuery.getSingleResult();
credentialEntity.setAccountId(uam.getAccountId());
return new UserAdapter(session, realm, model, credentialEntity);
} catch (Exception e) {
logger.error("Couldn't fetch user by id " + e.getMessage());
}
return null;
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
logger.info("getUserByUsername: " + username);
try {
TypedQuery<UserCredentialEntity> query = em.createQuery(GET_USER_FOR_USERNAME, UserCredentialEntity.class);
query.setParameter("username", username);
UserCredentialEntity credentialEntity = query.getSingleResult();
if (credentialEntity == null) {
logger.error("could not find username: " + username);
return null;
}
UserEntity entity = credentialEntity.getUserEntity();
if (entity == null) {
logger.error("Couldn't fetch user for given username ");
return null;
}
TypedQuery<UserAccountMapping> uamQuery = em.createQuery(GET_USER_ACCOUNT_MAPPING_FOR_OWNER,
UserAccountMapping.class);
uamQuery.setParameter("userId", entity.getUserId());
UserAccountMapping uam = uamQuery.getSingleResult();
if (uam == null) {
logger.error("Couldn't find an owner mapping for this user ");
return null;
}
credentialEntity.setAccountId(uam.getAccountId());
logger.info("Fetch USerCredentialEntity :: " + credentialEntity.toString());
return new UserAdapter(session, realm, model, credentialEntity);
} catch (Exception e) {
logger.error("Couldn't validate user credentials " + e.getMessage());
}
return null;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return null;
}
@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 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;
try {
UserCredentialModel cred = (UserCredentialModel) input;
String password = getPassword(user);
String encryptedPassword = Crypto.encryptSHA1(cred.getValue());
if (password != null) {
if (password.equals(encryptedPassword)) {
return true;
} else {
UserModel model = getUserByUsername(user.getUsername(), realm);
String currentPassword = getPassword(model);
boolean isPasswordValid = currentPassword.equals(encryptedPassword);
if (isPasswordValid) {
logger.info(
"It appears user has changed his password.Invalidating Cache and getting latest password from db");
((CachedUserModel) user).getCachedWith().put(PASSWORD_CACHE_KEY, currentPassword);
return isPasswordValid;
}
}
}
} catch (Exception e) {
logger.error("Couldn't validate user credentials " + e.getMessage());
}
return false;
}
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;
}
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
}