EJB3 JBossWS Authentication in 5.1.0 GA not working
tumuhairwe Oct 12, 2010 1:36 AMHi
I've read this [1] and [2] and [3] and a whole bunch of others (including the JBoss In Action book) and they all say the same thing:
1. Configure a data-source (*-ds.xml file)
2. Define a domain (conf/login-config.xml)
3. Tell the app about it:
a. put the <security-domain> in jboss-web.xml and in the
b. META-INF/jboss.xml
c. add a security constraint in web.xml
4. Annotate the EJB/Web-service with the security annotations (@SecurityDomain, @WebContext and @RolesAllowed in addition to @Stateless and @Webservice)
5. build, package & deploy as an ear
6. Add the values to the request-context map of the BindingProvider when calling...and everything should work.
But nothing is working for me i.e. I keep getting a 401 error (Unauthorized). (I've been struggling with this for days now) Question is can anyone see what I'm doing wrong.
Environment: Java version: 1.5.0_22, JBoss 5.1.0 GA, JBoss Web Services - Stack Native Core (3.1.2.GA)
conf/login-config.xml (fragment)
<application-policy name="verifiq-domain">
<authentication>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required">
<module-option name="dsJndiName">java:/VerifiqDS</module-option>
<module-option name="principalsQuery">SELECT password FROM verifiq.sys204_users_vw WHERE username=?</module-option>
<module-option name="rolesQuery">SELECT role, 'Roles' FROM verifiq.sys203_user_role_vw WHERE username=?</module-option>
<module-option name="unauthenticatedIdentity">anonymous</module-option>
</login-module>
</authentication>
</application-policy>
[still gives a HTTP 401 even if I use the default JBossWS]
The datasource (I've verified that this works)
<datasources>
<local-tx-datasource>
<jndi-name>VerifiqDS</jndi-name>
<connection-url>jdbc:postgresql://localhost:5432/tooro_eipp</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>THE-USERNAME</user-name>
<password>THE-PASSWORD</password>
</local-tx-datasource>
</datasources>
jboss-web.xml (the article [1] says its only for POJO's but it doesn't make a difference if I remove the <security-domain> tag)
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <class-loading java2ClassLoadingCompliance="false"> <loader-repository> <loader-repository-config> java2ParentDelegation=false </loader-repository-config> </loader-repository> </class-loading> <context-root>/verifiq</context-root> <security-domain flushOnSessionInvalidation="false">verifiq-domain</security-domain> </jboss-web>
jboss.xml (in the ejb jar's META-INF) Same as above i.e. doesn't make a difference if I uncomment.
<?xml version="1.0" encoding="UTF-8"?> <jboss> <security-domain>verifiq-domain</security-domain> <!-- <webservices> <context-root>/service</context-root> </webservices> <enterprise-beans> <session> <ejb-name>ExpulsionStatusBean</ejb-name> <jndi-name>ExpulsionStatusBean</jndi-name> <security-domain>verifiq-domain</security-domain> <port-component> <port-component-name>ExplusionStatusServicePort</port-component-name> <port-component-uri>/ExplusionStatusBeanPort</port-component-uri> <auth-method>BASIC</auth-method> <transport-guarantee>NONE</transport-guarantee> <secure-wsdl-access>false</secure-wsdl-access> </port-component> --> <!-- <resource-ref> <res-ref-name>jdbc/postgresql</res-ref-name> <jndi-name>java:/VerifiqDS</jndi-name> </resource-ref> --> <!-- <clustered>true</clustered> <cluster-config> <partition-name>DefaultPartition</partition-name> <load-balance-policy>org.jboss.ha.framework.interfaces.RandomRobin</load-balance-policy> </cluster-config> --> <!-- </session> </enterprise-beans> --> </jboss>
ExpulsionStatusBean.java [intentionally skipped the contextRoot in @WebContext because:
1. it puts the context (e.g. /service) outside the app's (/verifiq) i.e. security-constraint definitions in web.xml become useless since we now have localhost:8080/services and localhost:8080/verifiq.
2. It applies that service to all the web-services in that ejb jar (even though I've explicitly asked for a different contextRoot on another web-service)
Either way, even when I access them at a different location /services/serviceName?wsdl the result is the same i.e. HTTP 401]
@Stateless @WebService @Local(ExplusionStatusService.class) @SecurityDomain(value="JBossWS") @RolesAllowed("friend") @WebContext(authMethod="BASIC", transportGuarantee="NONE", secureWSDLAccess=false) public class ExplusionStatusBean implements ExplusionStatusService, Serializable { @Resource private SessionContext context; @WebMethod public String expell(@WebParam(name="person") Person person) { String retVal = "Expelling " + person.getSchoolAssignedID(); System.out.println("ExplusionStatusBean.expell(): invoked"); System.out.println("ExplusionStatusBean.expell(): Student: " + person); System.out.println("ExplusionStatusBean.expell(): caller: " + context.getCallerPrincipal()); System.out.println("ExplusionStatusBean.expell(): returning " + retVal); return retVal; } }
Expeller.java (snipped just main() )
public static void main(String[] args) { try { log.info("Constructing..."); ExplusionStatusBeanService esb = new ExplusionStatusBeanService(new URL("http://127.0.0.1:8080/verifiq-verifiq-ejb/ExplusionStatusBean?wsdl")); ExplusionStatusBean service = esb.getExplusionStatusBeanPort(); log.info("Computing password"); String password = "thefrog"; //password = DigestUtils.md5Hex(password); //String pass = log.info("Setting authentication info"); //BindingProvider bp = (BindingProvider)service; //Map<String, Object> authentication = bp.getRequestContext(); ((BindingProvider)service).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "kermit"); ((BindingProvider)service).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password); System.out.println("Using username kermit and password=" + password); log.info("Invoking..."); Person person = getJudes(); // Person is just a regular JPA pojo (mapped) (with name & schoolId) String response = service.expell(person); log.info("Response receieved successfully! " + response); } catch (Exception ex) { ex.printStackTrace(); log.log(Level.SEVERE, null, ex); } }
server.log
(I'm 100% certain the user kermit->thefrog exists in both the props/jbossws-*.properties file (when I use the default JBossWS) and in the database.)
2010-10-12 01:09:07,797 DEBUG [org.jboss.security.auth.spi.DatabaseServerLoginModule] (http-127.0.0.1-8080-1) Bad password for username=kermit
2010-10-12 01:09:07,797 DEBUG [org.jboss.security.auth.spi.DatabaseServerLoginModule] (http-127.0.0.1-8080-1) Bad password for username=kermit
Like I said, I'm 100% certain the kermit exists & has the role 'friend' (see attached screenshot)
Is there anything I'm missing?
web.xml (supposedly for POJOs only but I've included a snippet anyway. Doesn't matter if I comment or uncomment it out. Same result "Bad password" error)
<security-constraint> <web-resource-collection> <web-resource-name>All webservices</web-resource-name> <description>Protects all webservices</description> <url-pattern>/service</url-pattern> </web-resource-collection> <auth-constraint> <role-name>admissions-viewer</role-name> <role-name>friend</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>admissions-viewer</role-name> </security-role> <security-role> <role-name>friend</role-name> </security-role> <security-role> <role-name>admissions-manager</role-name> </security-role> <login-config> <auth-method>BASIC</auth-method> <realm-name>Verifiq Webservices Realm</realm-name> </login-config>
I've gone over it countless times & I'm just frustrated. It really shouldn't be that hard to get it to work...in theory :-)
Is there anything I'm missing?
TIA,
Judes Tumuhairwe
References:
[1] http://community.jboss.org/wiki/JBossWS-Authentication
[2] http://www.coderanch.com/t/477889/JBoss/Securing-Application-JBoss
[3] http://thatjavathing.blogspot.com/2009/05/authentication-and-authorization-with_30.html
-
webservices-screenshot.png 217.4 KB