I want to encrypt communications between a JBoss 6.1.0.Final server and my client. To do this I activated SSL over RMI and it works well. However, I use RMIIO too and it was not automatically encrypted when I activated SSL encryption over RMI. In a best case scenario, I would like to use the same encryption technique I used to encrypt RMI communications.
Here is my configuration:
server/myThing/deploy/remoting-jboss-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="UnifiedInvokerConnector" class="org.jboss.remoting.transport.Connector">
<annotation>#org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.remoting:service=Connector,transport=socket",exposedInterface=org.jboss.remoting.transport.ConnectorMBean.class,registerDirectly=true)</annotation>
<property name="serverConfiguration"><inject bean="UnifiedInvokerConfiguration"/></property>
<!-- add this to configure the SSL socket for the UnifiedInvoker -->
<property name="serverSocketFactory"><inject bean="SSLServerSocketFactoryEJB2"/></property>
</bean>
<!-- Remoting server configuration -->
<bean name="UnifiedInvokerConfiguration" class="org.jboss.remoting.ServerConfiguration">
<constructor>
<!-- Changed from socket to sslsocket -->
<parameter>sslsocket</parameter>
</constructor>
<!-- some other stuff, kept as the default config -->
</bean>
<!-- Some stuff removed to simplify the explanation -->
<!-- Added for SSL security -->
<bean name="SSLServerSocketFactoryEJB2" class="org.jboss.security.ssl.DomainServerSocketFactory">
<constructor>
<parameter><inject bean="EJB2SSLDomain"/></parameter>
</constructor>
</bean>
<!-- Added for SSL security -->
<bean name="EJB2SSLDomain" class="org.jboss.security.plugins.JaasSecurityDomain">
<constructor>
<parameter>EJB2SSLDomain</parameter>
</constructor>
<property name="keyStoreURL">C:\MyData\Security\ssl.keystore</property>
<property name="keyStorePass">MyPassword</property>
<property name="keyStoreAlias">MyAlias</property>
<property name="trustStorePass">MyPassword</property>
</bean>
</deployment>
server/myThing/deploy/properties-service.xml
<server>
<!-- some stuff removed -->
<mbean code="org.jboss.varia.property.SystemPropertiesService"
name="jboss:type=Service,name=SystemProperties">
<attribute name="Properties">
com.healthmarketscience.rmiio.exporter.port=11099
</attribute>
</mbean>
</server>
It's been awhile since i poked at RMI and SSL. However, RMIIO has a specific interface which allows you to customize the underlying "remoting" implementation, the RemoteStreamExporter. If you look at the DefaultRemoteStreamExporter implementation, you can see how the RMI objects are exported by default. My guess is that you want to use similar implementation which calls the 4 parameter export method with the appropriate RMI SSL socket factories.
Here is how I made it work, this was deduced from jtahlborn answer.
I got the JBoss config on RMI which is configured in remoting-jboss-beans.xml and initialise the SSLContext.setDefault with it. The code is called when JBoss is starting. Here is a simplified example of it.
KeyStore lKeyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
InputStream lISKeyStore = new FileInputStream( new File( "C:/Security/ssl.keystore" ) );
try
{
lKeyStore.load( lISKeyStore, "MyPassword".toCharArray() );
}
finally
{
lISKeyStore.close();
}
KeyManagerFactory lKeyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
lKeyManagerFactory.init(lKeyStore, "MyPassword".toCharArray() );
KeyStore lTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream lIStrustStore = new FileInputStream( new File( "C:/Security/ssl.truststore" ) );
try
{
lTrustStore.load(lIStrustStore, "MyPassword".toCharArray() );
}
finally
{
lIStrustStore.close();
}
TrustManagerFactory lTrustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
lTrustManagerFactory.init(lTrustStore);
SSLContext lSSLContext = SSLContext.getInstance( "SSL" ); // Don't use SSLContext.getDefault() here it seems it's immutable.
lSSLContext.init( lKeyManagerFactory.getKeyManagers(), lTrustManagerFactory.getTrustManagers(), null );
SSLContext.setDefault( lSSLContext );
I also created my own RemoteStreamExporter
public class SSLRemoteStreamExporter extends DefaultRemoteStreamExporter
{
#Override
protected Object exportImpl(RemoteStreamServer<?,?> server)
throws RemoteException
{
// The SslRMIServerSocketFactory uses SSLContext.getDefault() to retrieve the configuration. The default must be initialized with right values.
return UnicastRemoteObject.exportObject(server, getPort(), new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory() );
}
}
Afterward, I configured RMIIO to use my own RemoteStreamExporter
server/myThing/deploy/properties-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server>
<!-- $Id: properties-service.xml 16662 2003-08-27 04:38:22Z patriot1burke $ -->
<server>
<!-- some stuff removed -->
<mbean code="org.jboss.varia.property.SystemPropertiesService"
name="jboss:type=Service,name=SystemProperties">
<attribute name="Properties">
com.healthmarketscience.rmiio.exporter.port=11099
com.healthmarketscience.rmiio.exporter=SSLRemoteStreamExporter
</attribute>
</mbean>
</server>
Related
I am trying to implement a module to send messages from a CXF client to a server (SOAP endpoint) using HTTPS. I am able to achieve this by following the guide here: https://camel.apache.org/how-to-switch-the-cxf-consumer-between-http-and-https-without-touching-the-spring-configuration.html
The following configuration is key:
<ctx:property-placeholder location="classpath:orderEntry.cfg" />
<!-- other properties -->
<http:conduit name="{http://www.company.com/product/orderEntry/service/1}OrderEntry.http-conduit">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers>
<sec:keyStore type="JKS" password="${trustStore.password}" file="${trustStore.file}"/>
</sec:trustManagers>
<!-- other config -->
</http:tlsClientParameters>
</http:conduit>
The above configuration refers to a config file that has these properties stored:
orderEntry.cfg
--------------
endpointUri=https://localhost:8181/OrderEntry
trustStore.password=password
trustStore.file=etc/myApp.ts
As noted earlier, I am able to send messages via https when I follow the guide.
But I am concerned about the password being stored in plain text here. Is there a way that I can have the password wired from Java code (which can probably read the password from an encrypted source) and provide it to the http conduit when it needs it?
Have you tried location attribute value with file prefix?
E.g. location="file:/my/custom/location/orderEntry.cfg"
See: https://stackoverflow.com/a/17303537
Update:
If it works with your custom bean, you can try create trust managers as a bean and inject it into the conduit configuration like bellow:
blueprint.xml
<bean id="serviceTrustManager"
class="my.app.security.KeyStores" factory-method="loadTrustManagers">
<argument index="0" value="${my.app.service.trustStorePath}"/>
<argument index="1" value="${my.app.service.trustStoreEncryptedPassword}"/>
</bean>
<http:conduit name="{http://www.company.com/product/orderEntry/service/1}OrderEntry.http-conduit">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers ref="serviceTrustManager"/>
</http:tlsClientParameters>
</http:conduit>
Java code:
public class KeyStores {
public static TrustManager[] loadTrustManagers(String trustStorePath, String trustStoreEncryptedPassword) {
String trustStoreDecryptedPassword = PasswordDescriptor.decryptPassword(trustStoreEncryptedPassword); //Password decryption logic here
KeyStore trustStore = KeyStores.loadKeyStore("JKS", trustStorePath, trustStoreDecryptedPassword); //IO logic here
TrustManagerFactory trustFactory;
try {
trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
} catch (NoSuchAlgorithmException | KeyStoreException ex) {
throw new IllegalStateException(ex);
}
return trustFactory.getTrustManagers();
}
}
how do i proivde authentication data for spring data solr server?
Here is what i have in configuration
<solr:solr-server id="solrServer" url="http://xxxxxxxx:8983/solr" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate" scope="singleton">
<constructor-arg ref="solrServer" />
</bean>
<bean id="searchRepository" class="com.bankofamerica.atmtech.repository.SolrJournalRepository">
<property name="solrOperations" ref="solrTemplate" />
</bean>
<bean id="App" class="App">
<property name="repo" ref="searchRepository" />
</bean>
I don't see any property where i can set it.
You cannot set Credentials directly but have to go through the factory.
#Bean
SolrTemplate solrTemplate() {
return new SolrTemplate(solrServerFactory());
}
#Bean
SolrServerFactory solrServerFactory() {
Credentials credentials = new UsernamePasswordCredentials("foo", "bar");
return new HttpSolrServerFactory(solrServer(), "collection1", credentials , "BASIC");
}
#Bean
SolrServer solrServer() {
return new HttpSolrServer("http://localhost:8983/solr");
}
I guess some kind of SolrAuthenticationProvider picked up and applied if present in application context would make sense in this case.
I have downloaded the sample from http://mybatis.github.io/spring/sample.html.
1)I then open the pom.xml and imported it into intellij
2)I added a spring MVC facet
3) i added a web facet
4) i am using intellij 12.1.6
Once done, the autowiring is failing. I am trying to learn this new framework
All the service autowires have an error similar to::
Could not autowire. No beans of 'LineItemMapper' type found
public class OrderService {
#Autowired
private ItemMapper itemMapper;
#Autowired
private OrderMapper orderMapper;
#Autowired
private SequenceMapper sequenceMapper;
#Autowired
private LineItemMapper lineItemMapper;
I am thinking it is something i have setup incorrectly in my project.
this is the provided applicationCOntext from the example
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- in-memory database and a datasource -->
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:database/jpetstore-hsqldb-schema.sql"/>
<jdbc:script location="classpath:database/jpetstore-hsqldb-dataload.sql"/>
</jdbc:embedded-database>
<!-- transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- enable component scanning (beware that this does not enable mapper scanning!) -->
<context:component-scan base-package="org.mybatis.jpetstore.service" />
<!-- enable autowire -->
<context:annotation-config />
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven />
<!-- define the SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="org.mybatis.jpetstore.domain" />
</bean>
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.jpetstore.persistence" />
</bean>
</beans>
this is a zip of the project https://www.dropbox.com/s/lohr3udnm0oa2hn/mybatis-jpetstore-6.0.1-sources.zip
Hopefully someone can point me to what i am doing incorrectly
Thanks for any help
The first thing to do is to try using the latest version of IntelliJ, released earlier this week. It has improved support for spring.
The underlying problem is that you need to set up IntelliJ's spring facet and assign the application context groups.
I have a Java EE web application which uses an LDAP authentication. I use Spring security to connect to my LDAP with the following code:
<bean id="ldapContextSource" class="com.myapp.security.authentication.MySecurityContextSource">
<constructor-arg index="0" value="${ldap.url}" />
<constructor-arg index="1" ref="userConnexion" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
<constructor-arg value="${ldap.authJndiAlias}" />
</bean>
<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapContextSource" />
<property name="userSearch" ref="userSearch" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="com.myapp.security.authentication.MyAuthoritiesPopulator" >
<property name="userService" ref="userService" />
</bean>
</constructor-arg>
<property name="userDetailsContextMapper" ref="myUserDetailsContextMapper"/>
<property name="hideUserNotFoundExceptions" value="false" />
</bean>
Actually, my bean WebsphereCredentials uses a WebSphere private class WSMappingCallbackHandlerFactory as in this response : How to access authentication alias from EJB deployed to Websphere 6.1
We can see it in the official websphere documentation: http://pic.dhe.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Frsec_pluginj2c.html
But I don't want it because:
I think my application can access all JAAS logins in my WebSphere instance (not sure).
This class is defined in the HUGE IBM client library com.ibm.ws.admin.client-7.0.0.jar (42 Mo) => compilation slower, not present in my enterprise nexus
It's not portable, not standard
For information, I define the WebsphereCredentials constructor as this:
Map<String, String> map = new HashMap<String, String>();
map.put(Constants.MAPPING_ALIAS, this.jndiAlias);
Subject subject;
try {
CallbackHandler callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null);
LoginContext lc = new LoginContext("DefaultPrincipalMapping", callbackHandler);
lc.login();
subject = lc.getSubject();
} catch (NotImplementedException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
} catch (LoginException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
}
PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];
this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());
Is there a way to use just Spring security and remove this dependency?
I have no idea how to combine http://static.springsource.org/spring-security/site/docs/3.1.x/reference/jaas.html and http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ldap.html.
Maybe I must totally change my approach and use another way?
I assume your goal is to simply utilize the username / password that you configure in WebSphere to connect to the LDAP directory? If this is the case, you are not really trying to combine LDAP and JAAS based authentication. The JAAS support is really intended to be a way of using JAAS LoginModules to authenticate a user instead of using the LDAP based authentication.
If you are wanting to obtain the username and password without having a compile time dependency on WebSphere, you have a few options.
Eliminating Compile Time and Runtime Dependencies on WAS
One option is to configure the password in a different way. This could be as simple as using the password directly directly in the configuration file as shown in the Spring Security LDAP documentation:
<bean id="ldapContextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="password" value="password"/>
</bean>
You could also configure the username password in JNDI. Another alternative is to use a .properties file with the Property. If you are wanting to ensure the password is secured, then you will probably want to encrypt the password using something like Jasypt.
Eliminating Compile Time dependencies and still configuring with WAS
If you need or want to use WebSphere's J2C support for storing the credentials, then you can do by injecting the CallbackHandler instance. For example, your WebsphereCredentials bean could be something like this:
try {
LoginContext lc = new LoginContext("DefaultPrincipalMapping", this.callbackHandler);
lc.login();
subject = lc.getSubject();
} catch (NotImplementedException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
} catch (LoginException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
}
PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];
this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());
Your configuration would then look something like this:
<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
<constructor-arg ref="wasCallbackHandler"/>
</bean>
<bean id="wasCallbackHandler"
factory-bean="wasCallbackFactory"
factory-method="getCallbackHandler">
<constructor-arg>
<map>
<entry
value="${ldap.authJndiAlias}">
<key>
<util:constant static-field="com.ibm.wsspi.security.auth.callback.Constants.MAPPING_ALIAS"/>
</key>
</entry>
</map>
</constructor-arg>
<constructor-arg>
<null />
</constructor-arg>
</bean>
<bean id="wasCallbackFactory"
class="com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory"
factory-method="getInstance" />
Disclaimer
CallbackHandler instances are not Thread safe and generally should not be used more than once. Thus it can be a bit risky injecting CallbackHandler instances as member variables. You may want to program in a check to ensure that the CallbackHandler only used one time.
Hybrid Approach
You could do a hybrid approach that always removes the compile time dependency and allows you to remove the runtime dependency in instances where you might not be running on WebSphere. This could be done by combining the two suggestions and using Spring Bean Definition Profiles to differentiate between running on WebSphere and a non-WebSphere machine.
I'm embedding a Java EE 5 application using GlassFish 3.0.1. I already can deploy it (when using without specific configuration), but when trying to run server with the domain.xml (basically JAAS info), I get this error:
java.lang.IllegalArgumentException: URI is not absolute
My code is this (error points to the last line):
Server.Builder builder = new Server.Builder("ipc");
EmbeddedFileSystem.Builder efsb = new EmbeddedFileSystem.Builder();
File domainDir = new File( "domains/ipc-domain" );
File domainXML = new File( domainDir.getAbsoluteFile(), "config/domain.xml" );
efsb.instanceRoot( domainDir.getAbsoluteFile() );
efsb.configurationFile( domainXML.getAbsoluteFile() );
EmbeddedFileSystem efs = efsb.build();
builder.embeddedFileSystem(efs);
//Trying to set variable used at domain.xml (blind shot)
Properties props = new Properties();
props.setProperty( "com.sun.aas.instanceRoot" , domainDir.toURI().toString());
Server server = builder.build( props );
My domain.xml (specific part) have this:
<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0">
<system-applications/>
<applications>
<application context-root="/IPC" location="${com.sun.aas.instanceRoot}/applications/IPC/" name="IPC" object-type="user">
<property name="keepSessions" value="false"></property>
<property name="defaultAppName" value="IPC"></property>
<module name="IPC">
<engine sniffer="ejb"></engine>
<engine sniffer="security"></engine>
<engine sniffer="jpa"></engine>
<engine sniffer="web"></engine>
</module>
</application>
</applications>
<resources>
<jdbc-connection-pool pool-resize-quantity="1" datasource-classname="org.apache.derby.jdbc.ClientDataSource" max-pool-size="2" res-type="javax.sql.DataSource" steady-pool-size="1" name="ipc-pool">
<property name="PortNumber" value="1527"></property>
<property name="ServerName" value="0.0.0.0"></property>
<property name="User" value="app"></property>
<property name="Password" value="root"></property>
<property name="DatabaseName" value="IPC"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="ipc-pool" jndi-name="jdbc/IPC"></jdbc-resource>
</resources>
I've already tried to change the parts related to the "${com.sun.aas.instanceRoot}" variable, but then I have small variations of the URI error. Any insight?