Keycloak javax.ejb.EJBTransactionRolledbackException:用于KeyClope用户spi提供程序

Keycloak 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

下面是我的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</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;
    }
}