Hi,
In our previous demos we have already seen that how to remotely access the EJBs deployed on “JBoss AS 7.1.1.Final”. So in this example we will see how to invoke an EJB which is secured. Here we will use the “jboss-ejb3.xml” file which is a new container specific deployment descriptor for the EJBs. Also we will an alternative option of defining the security domain for our ejbs using annotation “@org.jboss.ejb3.annotation.SecurityDomain”
In this article we are going to see an easiest way to lookup a Secured EJBs remotely in >”JBoss AS7.1.1.Final”
Point-1). How to create a separate Security Realm for our EJBs inside “standalone-full.xml”.
Point-2). How to create a separate Security Domain for our EJBs inside “standalone-full.xml”.
Point-3). How to use the “jboss-ejb3.xml” file inside the EJB jar file in order to associate it with the security domain?
Point-4). How to use the annotation “@org.jboss.ejb3.annotation.SecurityDomain” sothat we will not need to write the addiaional deployment descriptor “jboss-ejb3.xml”
Point-5). A properties file need to be placed in the Clients CLASSPATH with name “jboss-ejb-client.properties”, with some additional properties.
The whole article will be divided into two Parts 1) the Server side configuration and 2). the Application Level Settings from the Client side.
Source Code (Git Repo) Source Code for this Demo Can be downloaded from GIT Repository:
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/Custom_SecurtyDomain_EJB3_AS711
JBossAS7 side configuration changes
Here we will first see what all changes are required from the JBoss side in order to create a separate Security Realm and Security Domain for our EJBs.
Step-1). Open the “$JBOSS_HOME/standaone/configuration/standalone-full.xml” file and then add a new Security Realm there inside the
<security-realm name="EJBRealm"> <authentication> <jaas name="ejb-security-domain"/> </authentication> </security-realm>
Step-2). As the above Security Realm is pointing to a security Domain “ejb-security-domain” so let’s create a new Security Realm inside the [subsystem xmlns=”urn:jboss:domain:security:1.1″] subsystem as following:
<security-domain name="ejb-security-domain" cache-type="default"> <authentication> <login-module code="Remoting" flag="optional"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required"> <module-option name="defaultUsersProperties" value="${jboss.server.config.dir}/ejb-users.properties"/> <module-option name="defaultRolesProperties" value="${jboss.server.config.dir}/ejb-roles.properties"/> <module-option name="usersProperties" value="${jboss.server.config.dir}/ejb-users.properties"/> <module-option name="rolesProperties" value="${jboss.server.config.dir}/ejb-roles.properties"/> <module-option name="password-stacking" value="useFirstPass"/> </login-module> </authentication> </security-domain>
Step-3). Also as we know that the EJBs are accessed remotely using the JBoss Remoting so we will need to make sure that the remoting subsystem is also using the Security Realm (EJBRealm) which we created as following:
<subsystem xmlns="urn:jboss:domain:remoting:1.1"> <connector name="remoting-connector" socket-binding="remoting" security-realm="EJBRealm"/> </subsystem>
Step-4). As our Security domain is using two properties file so we will need to create those properties file as well inside “$JBOSS_HOME/standaone/configuration/” as following:
ejb-users.properties
ejbUser=ejbPassword
ejb-roles.properties
ejbUser=ejbRole
Step-5). Now start the JBoss AS7.1.1.Final as following:
./standalone.sh -c standalone-full.xml
Developing Secure EJB3 Application
As the Server side configurations are done so now we will proceed with developing the Secure EJB3 application.
Step-6). Create a directory somewhere in your file system like “/home/userone/Custom_SecurtyDomain_EJB3_AS711” and then create another directory with name “src” inside the “/home/userone/Custom_SecurtyDomain_EJB3_AS711” directory.
Step-7). Write the EJB Stateless Bean class “CallerBean.java” as following inside the directory “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src”:
package remote; import javax.ejb.*; import javax.naming.*; import java.util.*; import javax.annotation.Resource; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RolesAllowed; import javax.ejb.LocalBean; import javax.ejb.SessionContext; @Stateless @Remote(CallerRemote.class) /* If you dont want to use "META-INF/jboss-ejb3.xml" then you can use the following annotation to defing your security-domain @org.jboss.ejb3.annotation.SecurityDomain("ejb-security-domain") */ public class CallerBean implements CallerRemote { @Resource private SessionContext sessionContext; @RolesAllowed("ejbRole") public String testMethod(String name) { System.out.println("nntBean's testMethod(String name) called...."); System.out.println("nntUserName: '" + sessionContext.getCallerPrincipal().getName() + "' is able to access testMethod()"); if (sessionContext.isCallerInRole("ejbRole")) System.out.println("tUser is in "ejbRole" "); else System.out.println("tUser is NOT in an allowed role"); return "[CallerBean] testMethod() returned Hello "+name; } public String commonMethod(String name) { System.out.println("nntBean's commonMethod(String name) called...."); System.out.println("nnUser " + sessionContext.getCallerPrincipal().getName() + " is able to access commonMethod()"); if (sessionContext.isCallerInRole("ejbRole")) System.out.println("t##### commonMethod() User is in ejbRole"); else System.out.println("t##### commonMethod() User is NOT in ejbRole"); return "[CallerBean] commonMethod() returned Hello "+name; } }
Step-8). Write the EJB Remote Interface “CallerRemote.java” as following inside the directory “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src”:
package remote; public interface CallerRemote { public String testMethod(String name); public String commonMethod(String name); }
Step-9). In order to secure the EJB we will define the security domain inside the “jboss-ejb3.xml” file. Spo create a file with this name inside “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src” as following:
<?xml version="1.0"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:s="urn:security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0"> <assembly-descriptor> <s:security> <ejb-name>*</ejb-name> <s:security-domain>ejb-security-domain</s:security-domain> </s:security> </assembly-descriptor> </jboss:ejb-jar>
Step-10). As we are going to create an EAR file containing the above Stateless Session Bean so We will write the “application.xml” as following inside the directory “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src”:
<?xml version="1.0" encoding="UTF-8"?> <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5"> <module> <ejb>remoteEJB.jar</ejb> </module> </application>
Developing EJB3 Remote Client
Step-11). Now we will write the Client side code to access the Above mentioned EJB Remotely so create a class “TestRemoteClientA.java” as following inside the directory “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src”:
package client; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.util.Properties; import remote.CallerRemote; public class TestRemoteClientA { public static void main(String ar[]) throws Exception { Context context=null; try { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); props.put(Context.PROVIDER_URL, "remote://localhost:4447"); props.put(Context.SECURITY_PRINCIPAL, "ejbUser"); props.put(Context.SECURITY_CREDENTIALS, "ejbPassword"); //props.put("jboss.naming.client.remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED","true"); //props.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS","true"); props.put("jboss.naming.client.ejb.context", true); props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false"); context = new InitialContext(props); System.out.println("nt--------------------------nGot initial Context: "+context); } catch (Exception e) { e.printStackTrace(); } // Lookup Format will be // <app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface> CallerRemote remote=(CallerRemote)context.lookup("TestRemoteEJBEAR/remoteEJB//CallerBean!remote.CallerRemote"); //System.out.println("nt remote.testMethod("Common-MiddlewareMagic") = "+remote.commonMethod("Common-MiddlewareMagic")); System.out.println("nt remote.testMethod("MiddlewareMagic") = "+remote.testMethod("MiddlewareMagic")); } }
Step-12). Almost everything is done, so we will create a client side logging file sothat we will get the desired logging at the Remote EJB Client side. So lets create a file “logging.properties” inside “/home/userone/Custom_SecurtyDomain_EJB3_AS711/src” as following:
# Logging handlers = java.util.logging.ConsoleHandler .level = ALL INFO # Console Logging java.util.logging.ConsoleHandler.level=SEVERE
Step-13). Now the most important part of building / deploying and running the application so in order to achieve that we will create a simple ant build script, So Create a “build.xml” file inside the “/home/userone/Custom_SecurtyDomain_EJB3_AS711” directory as following:
<project name="EJB3_SecurityDomain_Service" default="all"> <property name="jboss.home" value="/NotBackedUp/JBoss_All/jboss-as-7.1.1.Final" /> <property name="jboss.module.dir" value="${jboss.home}/modules" /> <property name="basedir" value="." /> <property name="tmp.dir" value="tmp" /> <property name="src.dir" value="src" /> <property name="output.dir" value="build" /> <property name="ear.name" value="TestRemoteEJBEAR.ear" /> <property name="ejb.jar" value="remoteEJB.jar" /> <property name="client.jar.name" value="remoteEJBClient.jar" /> <path id="jboss.classpath"> <fileset dir="${jboss.module.dir}"> <include name="**/*.jar"/> </fileset> </path> <!-- Client Needs the following Jar to be present in the CLASSPATH including --> <path id="jboss.new.client.classpath"> <fileset dir="${jboss.home}/bin/client" > <include name="jboss-client.jar" /> </fileset> </path> <target name="all" depends="deploy" /> <target name="build_ear"> <delete dir="${tmp.dir}" /> <mkdir dir="${tmp.dir}/META-INF" /> <javac srcdir="${src.dir}" destdir="${tmp.dir}" includes="*.java" excludes="TestRemoteClientA.java" classpathref="jboss.classpath"/> <copy file="${src.dir}/jboss-ejb3.xml" todir="${tmp.dir}/META-INF"/> <jar jarfile="${tmp.dir}/${ejb.jar}" basedir="${tmp.dir}" compress="true" /> <delete file="${tmp.dir}/ejb-users.properties"/> <delete file="${tmp.dir}/ejb-roles.properties"/> <delete file="${tmp.dir}/META-INF/jboss-ejb3.xml"/> <delete includeEmptyDirs="true"> <fileset dir="${tmp.dir}/remote"/> </delete> <mkdir dir="${tmp.dir}/META-INF"/> <copy todir="${tmp.dir}/META-INF"> <fileset dir="${src.dir}/"> <include name="application.xml"/> </fileset> </copy> <jar jarfile="${tmp.dir}/${ear.name}" basedir="${tmp.dir}" compress="true" /> <delete includeEmptyDirs="true"> <fileset dir="${tmp.dir}/META-INF"/> </delete> <delete file="${tmp.dir}/${ejb.jar}"/> <copy file="${tmp.dir}/${ear.name}" tofile="${output.dir}/${ear.name}"/> <delete file="${tmp.dir}/${ear.name}"/> </target> <target name="deploy" depends="build_ear"> <echo message="******************* Deploying the EAR file ${ear.name} *********************" /> <echo message="********** ${output.dir}/${ear.name} to ${jboss.home}/standalone/deployments **********" /> <copy todir="${jboss.home}/standalone/deployments/"> <fileset dir="${output.dir}/"> <include name="${ear.name}"/> </fileset> </copy> <echo message="******************* Deployed Successfully *********************" /> </target> <target name="run"> <delete dir="${tmp.dir}" /> <mkdir dir="${tmp.dir}" /> <javac srcdir="${src.dir}" destdir="${tmp.dir}" includes="CallerRemote.java,TestRemoteClientA.java" classpathref="jboss.classpath"/> <jar jarfile="${output.dir}/${client.jar.name}" basedir="${tmp.dir}" compress="true" /> <delete dir="${tmp.dir}"/> <java classname="client.TestRemoteClientA" fork="true"> <classpath> <pathelement location="${output.dir}/${client.jar.name}"/> <path refid="jboss.new.client.classpath"/> </classpath> <!-- Note Here we are passing the Client side logging related file to the JVM --> <sysproperty key="java.util.logging.manager" value="java.util.logging.LogManager"/> <sysproperty key="java.util.logging.config.file" value="${src.dir}/logging.properties"/> <sysproperty key="java.util.logging.ConsoleHandler.level" value="SEVERE" /> </java> </target> </project>
NOTE: The only change in the above file you need to do is to change the “jboss.home” directory path in the second line of the above script to point to your own JBoss AS7 directory.
Step-15). Now before running your ANT script to build and deploy the above webapplication you should have the ANT as well as JAVA set in the $PATH variable of the Shell / command prompt as following:
For Unix Based OS: export PATH=/home/userone/jdk1.6.0_21/bin:/home/userone/org.apache.ant_1.6.5/bin:$PATH For Windows Based OS: set PATH=C:/jdk1.6.0_21/bin;C:/org.apache.ant_1.6.5/bin;%PATH%
Step-16). Now once the PATH is set In the command/Shell prompt you can move inside the directory “/home/userone/Custom_SecurtyDomain_EJB3_AS711” and then run the ant to build and deploy the EJB based EAR applicationon your JBoss Standalone full profile, by running the command “ant deploy”
[userone@localhost Custom_SecurtyDomain_EJB3_AS711]$ ant deploy Buildfile: build.xml build_ear: [mkdir] Created dir: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/META-INF [javac] Compiling 2 source files to /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp [copy] Copying 1 file to /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/META-INF [jar] Building jar: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/remoteEJB.jar [delete] Deleting: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/META-INF/jboss-ejb3.xml [copy] Copying 1 file to /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/META-INF [jar] Building jar: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/TestRemoteEJBEAR.ear [delete] Deleting: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/remoteEJB.jar [copy] Copying 1 file to /home/userone/Custom_SecurtyDomain_EJB3_AS711/build [delete] Deleting: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp/TestRemoteEJBEAR.ear deploy: [echo] ******************* Deploying the EAR file TestRemoteEJBEAR.ear ********************* [echo] ********** build/TestRemoteEJBEAR.ear to /home/userone/jboss-as-7.1.1.Final//standalone/deployments ********** [copy] Copying 1 file to /home/userone/jboss-as-7.1.1.Final//standalone/deployments [echo] ******************* Deployed Successfully ********************* BUILD SUCCESSFUL Total time: 2 seconds
Step-17). Now we will try to compile and run the EJB3 remote Client application by running the command “ant run”
[userone@localhost Custom_SecurtyDomain_EJB3_AS711]$ ant run Buildfile: build.xml run: [delete] Deleting directory /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp [mkdir] Created dir: /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp [copy] Copying 1 file to /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp [javac] Compiling 2 source files to /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp [jar] Building jar: /home/userone/Custom_SecurtyDomain_EJB3_AS711/build/remoteEJBClient.jar [delete] Deleting directory /home/userone/Custom_SecurtyDomain_EJB3_AS711/tmp -------------------------- Got initial Context: javax.naming.InitialContext@5ff3ce5c remote.testMethod("MiddlewareMagic") = [CallerBean] testMethod() returned Hello MiddlewareMagic BUILD SUCCESSFUL Total time: 3 seconds
.
.
Thanks 🙂
Middleware Magic Team
March 13th, 2013 on 12:12 pm
After settiong EJBRealm as default for socket-binding=”remoting” not worked remote JMS-client (http://middlewaremagic.com/jboss/?p=2161) 🙁
May 30th, 2014 on 10:03 pm
I tried this tutorial and had two problems. First, I execute ant deploy and I got:
[javac] C:javaworkspace_newejbrealmbuild.xml:30: warning: ‘includeantruntime’ was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[copy] Copying 1 file to C:javaworkspace_newejbrealmtmpMETA-INF
[jar] Building jar: C:javaworkspace_newejbrealmtmpremoteEJB.jar
[delete] Deleting: C:javaworkspace_newejbrealmtmpMETA-INFjboss-ejb3.xml
BUILD FAILED
C:javaworkspace_newejbrealmbuild.xml:40: Directory does not exist: C:javaworkspace_newejbrealmtmpremote
Second,
When I start server JBoss I got:
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: JBAS011555: Failed to configure logging using ‘logging.properties’ configuration file.
at org.jboss.as.logging.LoggingConfigurationProcessor.deploy(LoggingConfigurationProcessor.java:125)
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:116) [jboss-as-server-7.1.2.Final-redhat-1.jar:7.1.2.Final-redhat-1]
… 5 more
Caused by: java.lang.IllegalArgumentException: className is null
at org.jboss.logmanager.config.AbstractPropertyConfiguration.(AbstractPropertyConfiguration.java:52) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.logmanager.config.HandlerConfigurationImpl.(HandlerConfigurationImpl.java:54) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.logmanager.config.LogContextConfigurationImpl.addHandlerConfiguration(LogContextConfigurationImpl.java:138) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.logmanager.PropertyConfigurator.configureHandler(PropertyConfigurator.java:477) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.logmanager.PropertyConfigurator.configure(PropertyConfigurator.java:379) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.logmanager.PropertyConfigurator.configure(PropertyConfigurator.java:92) [jboss-logmanager-1.3.1.Final-redhat-1.jar:1.3.1.Final-redhat-1]
at org.jboss.as.logging.LoggingConfigurationProcessor.deploy(LoggingConfigurationProcessor.java:122)
Do you know what happens?
Thanks
February 5th, 2016 on 1:03 pm
Hi,
When executing the client I am getting below exception
javax.naming.AuthenticationException: Failed to connect to any server. Servers tried: [remote://localhost:4447 (Authentication failed: all available authentication mechanisms failed:
JBOSS-LOCAL-USER: Server rejected authentication)] [Root exception is javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed:
JBOSS-LOCAL-USER: Server rejected authentication]
Any help!!!
February 5th, 2016 on 1:08 pm
Hello Srikanth,
I am assuming that you are either using JBossAS7 or EAP6.x. Which uses “ApplicationRealm” by default for the authentication of the remoting socket 4447. So if you want to connect to the remoting port then you should be creating a user in the “ApplicationRealm” using the add-user.sh script as following:
cd $JBOSS_HOME/bin
./add-user.sh -a testUser testUserPWD1!
Here “-a” indicate that add the user in the ApplicationRealm and the “testUserPWD1!” is the password, similarly the “testUser” is the username. So please check if you are passing the correct credentials or not.
Regards
Jay SenSharma
February 5th, 2016 on 1:33 pm
Hi Jay,
Thank you very much for your quick response.
Yes I am using Jboass as 7.1.1.Final. As you mentioned in the post I’ve modified remoting socket to use “EJBRealm”. Below is the snippet for this in my standlone file
Just got struck here, Please help!!!
Thanks in advance!!
February 5th, 2016 on 1:54 pm
Hello Srikanth,
Looks like the standalone.xml snippet is not copied correctly in your last update as it might be having the XML syntax. May be you can replace all the < and > characters with some other characters. and then post. Also can you please post the complete stackTrace of the exception here along with the code snippet.
Regards
Jay SenSharma
February 5th, 2016 on 2:41 pm
Hi Jay,
standalone changes (Replace LT for less than symbol and RT for greater than symbol)
1. declaring realm
LTsecurity-realm name=”EJBRealm”RT
LTauthenticationRT
LTjaas name=”demosecuritydomain”/RT
LT/authenticationRT
LT/security-realmRT
February 5th, 2016 on 2:43 pm
2. remoting realm change
LTsubsystem xmlns=”urn:jboss:domain:remoting:1.1″RT
LTconnector name=”remoting-connector” socket-binding=”remoting” security-realm=”EJBRealm”/RT
LT/subsystemRT
February 5th, 2016 on 2:49 pm
EJB class
@Remote(EjbSecurityDemo.class)
@Stateless
@SecurityDomain(“demosecuritydomain”)
@RolesAllowed({“user”, “admin”})
public class EjbSecurityDemoBean implements EjbSecurityDemo {
@Inject EjbSecurityDemoService service;
public User fetchMyContactDetails() {
return service.fetchMyContactDetails();
}
@RolesAllowed(“admin”)
public User fetchUserContactDetails(String userId) {
return service.fetchUserContactDetails(userId);
}
}
February 5th, 2016 on 2:51 pm
EJB client code
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, “org.jboss.naming.remote.client.InitialContextFactory”);
properties.put(Context.PROVIDER_URL, “remote://localhost:4447”);
properties.put(Context.SECURITY_PRINCIPAL, “admin”);
properties.put(Context.SECURITY_CREDENTIALS, “password”);
properties.put(“jboss.naming.client.ejb.context”, true);
Context context = new InitialContext(properties);
EjbSecurityDemo demoBean = (EjbSecurityDemo) context.lookup(“ejb3securitydemo/ejb3securitydemo-services-1.0-SNAPSHOT/EjbSecurityDemoBean!com.sample.ejb3securitydemo.ejb.EjbSecurityDemo”);
February 5th, 2016 on 2:55 pm
Exception trace:
javax.naming.AuthenticationException: Failed to connect to any server. Servers tried: [remote://localhost:4447 (Authentication failed: all available authentication mechanisms failed:
JBOSS-LOCAL-USER: Server rejected authentication)] [Root exception is javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed:
JBOSS-LOCAL-USER: Server rejected authentication]
Not able to post whole trace