11 Replies Latest reply on Jun 5, 2014 9:25 AM by rhauch

    How to encrypt Database password in modeshapeConf.xml

    deepak_a

      All,

       

      I am using Modeshape 2.7.0

      Component I use is: modeshape-connector-filesystem

       

      modeshapeConf.xml holds the database connection details

       

             <mode:source jcr:name="store" mode:autoGenerateSchema="disable"

          mode:classname="org.modeshape.connector.store.jpa.JpaSource"

          mode:compressData="false" mode:creatingWorkspacesAllowed="true"

          mode:defaultWorkspaceName="default" mode:dialect="org.hibernate.dialect.Oracle10gDialect"

          mode:driverClassName="oracle.jdbc.OracleDriver" mode:largeValueSizeInBytes="10000"

          mode:maximumConnectionsInPool="5" mode:model="Simple" mode:password="XXXXX"

          mode:predefinedWorkspaceNames="default,system" mode:referentialIntegrityEnforced="true"

          mode:retryLimit="3" mode:showSql="false" mode:url="jdbc:oracle:thin:@localhost:1521:xe" mode:username="XXXXX"/>

       

       

      I am trying to find out if there is a way I can store encrypted passsword in modeshapeconf.xml?

       

      As I understand we don't explicitly use API to let modeshape connect to the backend database - its all taken care by the framework.

       

      Is there a way to store encrypted password and specify the encryption algorithm so that modeshape API can handle it? or is there a way to override the default behavior?

       

       

      Note if its not possible to achieve this in 2.7 - can some one clarify if a later version of Modeshape supports this feature? (and what version if its supported)

       

      regards,

      Deepak

        • 1. Re: How to encrypt Database password in modeshapeConf.xml
          rhauch

          The only way is if you have JNDI available and can register a DataSource in JNDI. Then you can use the "mode:dataSourceJndiName" property to specify the JNDI name of the data source rather than specifying the connection details.

          • 2. Re: How to encrypt Database password in modeshapeConf.xml
            deepak_a

            Is it possible to access a JNDI set up in a remote JVM?

            I have a JBoss app server in a different JVM that has the JNDI datasource set up for the same database as Modeshale needs to connect to - is it possible to refer a JNDI in remote JVM?

            • 3. Re: How to encrypt Database password in modeshapeConf.xml
              rhauch

              No, it's not.

              • 4. Re: How to encrypt Database password in modeshapeConf.xml
                deepak_a

                Hi.

                 

                I have set up a local JNDI (in my J2SE app). And I have updated modeshape-conf.xml to refer the JNDI.

                 

                I can confirm the JNDI can be accessed by a test class (so JNDI is definitely set up).

                 

                But modeshape still says: javax.naming.NameNotFoundException: jdbc not bound

                 

                As per the below link:

                 

                https://docs.jboss.org/author/display/MODE/Using+ModeShape#UsingModeShape-RepositoryFactoryandJNDI

                One of the more popular ways to find a Repository instance is to use JNDI, though this only works in environments like web servers or application servers that contain a JNDI implementation. It also assumes that a Repository instance has already been registered in JNDI; how this is done is specific to the environment.


                Does this mean - I can't use modeshape in a J2SE environment (without web server or app server)? Pls clarify.


                I would be reluctant to use an app server just for this.


                regards,

                Deepak.

                • 5. Re: How to encrypt Database password in modeshapeConf.xml
                  rhauch

                  As per the below link:

                   

                  https://docs.jboss.org/author/display/MODE/Using+ModeShape#UsingModeShape-RepositoryFactoryandJNDI

                  One of the more popular ways to find a Repository instance is to use JNDI, though this only works in environments like web servers or application servers that contain a JNDI implementation. It also assumes that a Repository instance has already been registered in JNDI; how this is done is specific to the environment.


                  Does this mean - I can't use modeshape in a J2SE environment (without web server or app server)? Pls clarify.

                  You absolutely CAN use ModeShape within a JavaSE environment, and many people do. While standard JavaSE doesn't provide JNDI out of the box, some JavaSE environments and/or third-party libraries do provide JNDI behavior. That means that with 2.x you would be able to specify a DataSource via JNDI only if your environment has JNDI. ModeShape 3.x can do a few more things with JNDI (like automatically registering the repository in JNDI as described in the documentation), but obviously it only does this if JNDI if it is available within the environment.

                   

                  Now, you did say earlier that you're using ModeShape 2.70, but the link you provided is actually for the 3.x codebase. So while the information in that link is still incorrect, be sure that you're looking at the right documentation set for the version you're using.

                   

                  The 2.7.x documentation is available here: https://docs.jboss.org/author/display/MODE27/Home

                  The 2.8.x documentation is available here: https://docs.jboss.org/author/display/MODE28/Home

                  The 3.x documentation for all 3.x releases (3.0-3.8.0) is available here: https://docs.jboss.org/author/display/MODE/Home

                  The documentation for the 4.x releases (4.0.0.Alpha3) is available here: https://docs.jboss.org/author/display/MODE40/Home

                  1 of 1 people found this helpful
                  • 6. Re: How to encrypt Database password in modeshapeConf.xml
                    deepak_a

                    Hi,

                     

                    Thanks for clarifying that.

                     

                    I am still getting a NameNoFoundException. I think its likely because I am not passing in the JNDI context properties correctly to the Properties. Is there any example you can point to? especially on how context properties are passed in/set prior to loading the modeshapeConfig.xml

                     

                    [2014-06-03 17:02:22,826 modeshape-start-repo-2-thread-1] NamingHelper                   INFO  JNDI InitialContext properties:{}

                    [2014-06-03 17:02:22,830 modeshape-start-repo-2-thread-1] DatasourceConnectionProvider   ERROR Could not find datasource: jdbc/reformDS

                    javax.naming.NameNotFoundException: jdbc not bound

                     

                    This is what i do

                     

                            Properties props = new Properties();

                            props.put("modeShapeConfigURL", "classpath:modeShapeConf.xml");

                            //Do I need the below 2 properties to be set?

                              props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");

                             props.put(Context.PROVIDER_URL, "jnp://" + "localhost" + ":1099");

                          

                     

                    and in my modeshapeConf.xml I have the following

                     

                            <mode:source jcr:name="store" mode:autoGenerateSchema="disable" mode:classname="org.modeshape.connector.store.jpa.JpaSource" mode:compressData="false" mode:creatingWorkspacesAllowed="true" mode:dataSourceJndiName="jdbc/reformDS" mode:defaultWorkspaceName="default" mode:dialect="org.hibernate.dialect.Oracle10gDialect" mode:largeValueSizeInBytes="10000" mode:model="Simple" mode:predefinedWorkspaceNames="default,system" mode:referentialIntegrityEnforced="true" mode:retryLimit="3" mode:showSql="false"/>

                     

                    I have also tried with

                     

                            <mode:source jcr:name="store" mode:autoGenerateSchema="disable" mode:classname="org.modeshape.connector.store.jpa.JpaSource" mode:compressData="false" mode:creatingWorkspacesAllowed="true" mode:dataSourceJndiName="java:jdbc/reformDS" mode:defaultWorkspaceName="default" mode:dialect="org.hibernate.dialect.Oracle10gDialect" mode:largeValueSizeInBytes="10000" mode:model="Simple" mode:predefinedWorkspaceNames="default,system" mode:referentialIntegrityEnforced="true" mode:retryLimit="3" mode:showSql="false"/>

                     

                     

                     

                    I do the following to test if the JNDI context is available and it works perfect -

                     

                            final Hashtable<String, String> _properties = new Hashtable<String, String> ();

                            _properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");

                            _properties.put(Context.PROVIDER_URL,            "jnp://" + "localhost" + ":1099");

                            try {

                            final Context _context = new InitialContext(_properties);

                          Object obj = _context.lookup("jdbc/reformDS");

                          if (null != obj) {

                          System.out.println("OBJ: " + obj.getClass());

                          org.apache.commons.dbcp.BasicDataSource ds = (org.apache.commons.dbcp.BasicDataSource)obj;

                          JdbcTemplate jdbcTemplate2 = new JdbcTemplate(ds);

                              String sql = String.format("update MESSAGE_LOG set PROCESS_INSTANCE_ID = 123456 where ID =42395 ");      

                          } else {

                          }       

                            } catch (Exception e) {

                            e.printStackTrace();

                            }

                    • 7. Re: How to encrypt Database password in modeshapeConf.xml
                      rhauch

                      What's the library that is providing JNDI in your JavaSE app? You can see the code for the JNDI lookup in 2.7.0.Final here: https://github.com/ModeShape/modeshape/blob/modeshape-2.7.0.Final/extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaSource.java#L1313

                       

                      Perhaps try code exactly like that? Notice that we're not passing any properties to the InitialContext - is there any way to do that with the JNDI library you're using?

                       

                      Worse comes to worse, you could subclass the JpaSource class and override that method.

                      • 8. Re: How to encrypt Database password in modeshapeConf.xml
                        deepak_a

                        Hi,

                         

                        Thanks for pointing to the source code.

                        The library I use for starting the JNDI server has the following classes (used to start the JNDI server)

                        import org.jnp.server.Main;

                        import org.jnp.server.NamingBeanImpl;

                         

                        //Snippet of the code

                         

                                System.setProperty("java.rmi.server.hostname", "localhost");
                                System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
                                System.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
                                final NamingBeanImpl namingInfo = new NamingBeanImpl();       
                                namingInfo.start();
                               
                                final Main jndiServer = new Main();

                         

                         

                                jndiServer.setNamingInfo(namingInfo);
                                jndiServer.setPort(1099);
                                jndiServer.setBindAddress("localhost");
                                jndiServer.setRmiPort(1098);
                                jndiServer.setRmiBindAddress("localhost");
                                jndiServer.start();  
                                final Hashtable<String, String> _properties = new Hashtable<String, String> ();
                                _properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
                                _properties.put(Context.PROVIDER_URL,            "jnp://" + "localhost" + ":1099");
                                final Context _context = new InitialContext(_properties);
                                _context.createSubcontext("jdbc");
                                JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
                                System.out.println("jdbcTemplate:  " + jdbcTemplate.getClass());
                                System.out.println("getDataSource(): " + getDataSource().getClass());
                                _context.bind("/jdbc/reformDS", getDataSource());

                         

                        //JNDI started

                        //Test the JNDI Context Tree

                                final Hashtable<String, String> _properties = new Hashtable<String, String> ();

                                _properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");

                                _properties.put(Context.PROVIDER_URL,            "jnp://" + "localhost" + ":1099");

                         

                        final Context _context = new InitialContext(_properties);

                        Object obj = _context.lookup("/jdbc/reformDS");

                        if (null != obj) {

                        System.out.println("OBJ: " + obj.getClass());

                                       org.apache.commons.dbcp.BasicDataSource ds = (org.apache.commons.dbcp.BasicDataSource)obj;

                                       JdbcTemplate jdbcTemplate2 = new JdbcTemplate(ds);

                                       String sql = String.format("update MESSAGE_LOG set PROCESS_INSTANCE_ID = 123456 where ID =42395 ");      

                                       int update = jdbcTemplate2.update(sql);

                                       System.out.println("Update*****************: " + update);

                                       }

                         

                         

                         

                        In the test code where I extract the object from JNDI context - I "must" pass the JNDI host/port details - otherwise its not able to find the JNDI context.

                        I am curious to find how the method getConnection() in class JpaSource knows where/how to get the JNDI context? Is the host/port details passed in via a JNDI.properties file?

                         

                        regards,

                        Deepak.

                        • 9. Re: How to encrypt Database password in modeshapeConf.xml
                          rhauch

                          In the test code where I extract the object from JNDI context - I "must" pass the JNDI host/port details - otherwise its not able to find the JNDI context.

                          I am curious to find how the method getConnection() in class JpaSource knows where/how to get the JNDI context? Is the host/port details passed in via a JNDI.properties file?

                          The JpaSource class just create an InitialContext with the default constructor. That normally works in app/web server environments that come with JNDI. If I had to do it over again, I'd use a protected method to obtain the Context so that it's easier to subclass, and maybe even provide a way for properties to be defined and passed into the InitialContext.

                           

                          But 2.x is no longer a supported/maintained version. You can, however, just create a subclass of JpaSource that overrides the method that does what you need. (I'd suggest copy the existing code for the method and in your overridden method just change how InitialContext is constructed by passing in properties, which you can determine from new fields in your JpaSource subclass that you can then set in the configuration file -- or even hard code if that's good enough for your application.)

                          • 10. Re: How to encrypt Database password in modeshapeConf.xml
                            deepak_a

                            Hi,

                             

                            Thanks for the pointer. I looked up the source code for InitialContext

                             

                            http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/javax/naming/InitialContext.java#InitialContext.init%28java.util.Hashtable%29

                             

                            191    public More ...InitialContext() throws NamingException {

                            192        init(null);

                            193    }

                             

                            The init method in turn calls

                            http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/com/sun/naming/internal/ResourceManager.java#ResourceManager.getInitialEnvironment%28java.util.Hashtable%29

                             

                            That method seems to loop over all System.properties and picks up only those properties needed for JNDI.

                            So all I had to do was set the required properties just before modeshapeConf,xml is loaded

                             

                            i.e.

                            System.getProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");

                            System.getProperty(Context.PROVIDER_URL,            "jnp://" + "localhost" + ":1099");

                             

                            Now I am able to load the InitialContext even without passing the environment details via its constructor,

                            1 of 1 people found this helpful
                            • 11. Re: How to encrypt Database password in modeshapeConf.xml
                              rhauch

                              [The InitialContext()] method seems to loop over all System.properties and picks up only those properties needed for JNDI.

                              So all I had to do was set the required properties just before modeshapeConf,xml is loaded

                               

                              i.e.

                              System.getProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");

                              System.getProperty(Context.PROVIDER_URL,            "jnp://" + "localhost" + ":1099");

                               

                              Now I am able to load the InitialContext even without passing the environment details via its constructor,

                              Great tip. Thanks!