2014-10-20 47 views
2

我正在開發一個使用Jboss wildfly 8.1和JPA Hibernate的服務器應用程序。問題是,JPA數據源信用必須在運行時加載(密碼)。當服務器啓動時,它連接到一個加密的存儲器,在該存儲器中它將檢索密碼到真實數據庫。之後,它應該建立與真實數據庫的連接。Wildfly - 在運行時設置數據源密碼

我嘗試了幾件事情: 通過JNDI查找數據源,並用實際的DS重新綁定它。 通過JNDI查找entityManagerFactory並使用自定義EntityManager重新綁定它。

但這些都沒有工作。你有想法如何解決它?

我的配置:

的persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0"> 
    <persistence-unit name="PERSISTENCE_UNIT" transaction-type="JTA"> 
     <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 

     <jta-data-source>java:jboss/datasources/Datasource</jta-data-source> 
     ...classes... 

     <properties> 
     <!-- Properties for Hibernate -->    
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/> 
     <property name="hibernate.hbm2ddl.auto" value="update"/> 
     <property name="hibernate.show_sql" value="false"/> 
     <property name="hibernate.format_sql" value="false"></property> 
     <property name="hibernate.connection.useUnicode" value="true"/> 
     <property name="hibernate.connection.characterEncoding" value="UTF-8"/> 
     <property name="hibernate.connection.charSet" value="UTF-8"/> 
     <property name="org.hibernate.flushMode" value="commit" /> <!-- THIS ONE IS IMPORTANT --> 

     <property name="jboss.entity.manager.factory.jndi.name" value="java:/EntityManagerFactory"/> 
     <property name="jboss.entity.manager.jndi.name" value="java:/Manager1"/> 
     </properties>  
    </persistence-unit> 
</persistence> 

數據源(在standalone.xml定義):

  <datasource jndi-name="java:jboss/datasources/Datasource" pool-name="DS" enabled="true" use-java-context="true"> 
       <connection-url>jdbc:mysql://localhost:3306/repository</connection-url> 
       <connection-property name="useCompression"> 
        false 
       </connection-property> 
       <connection-property name="logSlowQueries"> 
        false 
       </connection-property> 
       <connection-property name="zeroDateTimeBehavior"> 
        convertToNull 
       </connection-property> 
       <connection-property name="characterEncoding"> 
        utf8 
       </connection-property> 
       <connection-property name="useUnicode"> 
        true 
       </connection-property> 
       <connection-property name="connectionCollation"> 
        utf8_unicode_ci 
       </connection-property> 
       <driver>mysql</driver> 
       <security> 
        <user-name>user</user-name> 
        <password>TO_BE_DEFINED</password> 
       </security> 
      </datasource> 

訪問實體管理器:

@Stateless 
@Local 
public class GenericDataBean { 

    @PersistenceContext(type=PersistenceContextType.TRANSACTION) 
    private EntityManager em; 

... 
} 

回答

1

甲可能的方案對於您的問題,請使用security domain作爲datasource。 在你的情況下,你必須創建custom login module負責從加密存儲加載密碼。
你的配置應該類似於。

數據源:

<datasource ... > 
    ..... 
    <security> 
      <security-domain>EncryptedPassword</security-domain> 
    </security> 
</datasource> 

安全Donain:

<security-domain name="EncryptedPassword"> 
    <authentication> 
     <login-module code="com.example.EncryptedPasswordLoginModule" flag="required"> 
      <!-- list of options --> 
      <module-option name="username" value="theusername"/> 
      <module-option name="managedConnectionFactoryName" value="jboss.jca:service=LocalTxCM,name=DS"/> 
     </login-module> 
    </authentication> 
</security-domain> 

登錄模塊實現:

public class EncryptedPasswordLoginModule 
    extends AbstractPasswordCredentialLoginModule{ 

    private String username; 

    public void initialize(Subject subject, CallbackHandler handler, Map sharedState, Map options){ 
     super.initialize(subject, handler, sharedState, options); 
     username = (String) options.get("username"); 
     if(username == null){ 
      throw new IllegalArgumentException("The user name is a required option"); 
     } 

    } 

    public boolean login() throws LoginException{ 
     if(super.login() == true) 
      return true; 

     super.loginOk = true; 
     return true; 
    } 

    public boolean commit() throws LoginException{ 
     Principal principal = new SimplePrincipal(username); 
     SubjectActions.addPrincipals(subject, principal); 
     sharedState.put("javax.security.auth.login.name", username); 
     try{ 
      char[] password = .... //code to load encrypted password; 
      PasswordCredential cred = new PasswordCredential(username, password); 
      cred.setManagedConnectionFactory(getMcf()); 
      SubjectActions.addCredentials(subject, cred); 
     } 
     catch(Exception e){ 
      throw new LoginException("Failed to load encrypted password: "+e.getMessage()); 
     } 
     return true; 
    } 

    public boolean abort(){ 
     username = null; 
     return true; 
    } 

    protected Principal getIdentity(){ 
     Principal principal = new SimplePrincipal(username); 
     return principal; 
    } 

    protected Group[] getRoleSets() throws LoginException{ 
     Group[] empty = new Group[0]; 
     return empty; 
    } 
} 

也許這可以提供幫助。

+0

謝謝你的回答。我現在會嘗試併發布結果。 – tNRevan 2014-10-21 08:23:14

0

你如何訪問類SubjectActions?類訪問修飾符是默認的,所以它在編譯時錯誤時拋出錯誤:class EncryptedPasswordLoginModule是公共的,應該在名爲EncryptedPasswordLoginModule.java的文件中聲明