1

First the code:

Application setting class:

    @ApplicationPath("/rest")
    public class ApplicationConfig extends Application {

    }

JAX-RS resource class:

    @Path("/test")
    @RequestScoped
    public class TestWS {
        @POST
        @Path("/login")
        @Produces(MediaType.TEXT_PLAIN)
        public Response login(@Context HttpServletRequest req){
            req.getSession().setAttribute("test","test");
            System.out.println(req.getSession().getId());
            if(req.getUserPrincipal() == null){
                String authHeader = req.getHeader(HttpHeaders.AUTHORIZATION);
                if(authHeader != null && !authHeader.isEmpty()){
                    String base64Credentials = authHeader.substring("Basic".length()).trim();
                    String credentials = new String(Base64.getDecoder().decode(base64Credentials),
                            Charset.forName("UTF-8"));
                    final String[] values = credentials.split(":",2);
                    try {
                        req.login(values[0], values[1]);
                        System.out.println(req.getUserPrincipal().toString());
                    }
                    catch(ServletException e){
                        e.printStackTrace();
                        return Response.status(Response.Status.UNAUTHORIZED).build();
                    }
                }
            }else{
                System.out.println(req.getUserPrincipal());
                System.out.println(req.isUserInRole("User"));
                req.getServletContext().log("Skipped logged because already logged in!");
            }

            req.getServletContext().log("Authentication Demo: successfully retrieved User Profile!");
            return Response.ok().build();
        }

        @Path("/ping")
        @Produces(MediaType.APPLICATION_JSON)
        @GET
        public String ping(@Context HttpServletRequest req){
            Object test = req.getSession().getAttribute("test");
            System.out.println(req.getSession().getId());
            System.out.println(test);
            System.out.println(req.getUserPrincipal());
            System.out.println(req.isUserInRole("User"));
            return "{\"status\":\"ok\"}";
        }
    }

web.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <web-app>
        <context-param>
            <param-name>resteasy.role.based.security</param-name>
            <param-value>true</param-value>
        </context-param>

        <security-constraint>
            <web-resource-collection>
                <web-resource-name>rest</web-resource-name>
                <url-pattern>/rest/*</url-pattern>
                <http-method>GET</http-method>
                <http-method>POST</http-method>
                <http-method>PUT</http-method>
                <http-method>DELETE</http-method>
            </web-resource-collection>
            <user-data-constraint>
                <transport-guarantee>NONE</transport-guarantee>
            </user-data-constraint>
        </security-constraint>

        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>

        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>

        <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>PBKDF2DatabaseDomain</realm-name>
        </login-config>
    </web-app>

jboss-web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web>
        <context-root>/</context-root>
        <security-domain>PBKDF2DatabaseDomain</security-domain>
    </jboss-web>

security settings in standalone.xml

    <subsystem xmlns="urn:jboss:domain:security:1.2">
        <security-domains>
            <security-domain name="PBKDF2DatabaseDomain" cache-type="default">
                <authentication>
                    <login-module code="de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule" flag="required" module="de.rtner.PBKDF2">
                        <module-option name="dsJndiName" value="java:jboss/datasources/developmentDS"/>
                        <module-option name="principalsQuery" value="SELECT password FROM ur.user WHERE username=?"/>
                        <module-option name="rolesQuery" value="select distinct r.NAME, 'Roles' from ur.user_roles ur left join ur.ct_role r on ur.ROLE_ID = r.ID left join ur.user u on ur.USER_ID = u.ID where u.username =?"/>
                    </login-module>
                </authentication>
            </security-domain>
...

Now my problem is that after I use /login method with BASIC auth header in request I already get user principal so it prints out:

Skipped logged because already logged in!

And if I remove BASIC auth header from request and I call login again I still get the same print out - so I already have user principal in request - no need to req.login.

BUT if I call ping method user principal is null even tho session id is the same and session attribute is set. What am I doing wrong? I would like that user principal would persist on /ping like it does on /login.

I am using Wildfly 10 (RESTeasy jax-rs implementation)

My question is similalr to: JBOSS AS7 jax-rs jaas and annotations

But the fix - setting session attribute in login method didn't work for me.

Community
  • 1
  • 1
BizzyDizzy
  • 279
  • 1
  • 4
  • 9
  • Basic auth. is `stateless`. If you explicitly config it to persist/cache, it will be saved. Try to separate form auth. and Basic auth. – Valijon Nov 23 '15 at 14:30
  • How is it stateless if it persists over the same resource (test/login) - second call to test/login is without AUTH header... – BizzyDizzy Nov 23 '15 at 14:44
  • Also I can't seem to find any documentation on how to configure basic auth to not be stateles - to persist/cache... – BizzyDizzy Nov 23 '15 at 14:50
  • I didnt try it with JBOSS, but with tomcat, I use like in this example [http://forum.spring.io/forum/spring-projects/security/123247-sec-http-basic-without-form-login](http://forum.spring.io/forum/spring-projects/security/123247-sec-http-basic-without-form-login) – Valijon Nov 23 '15 at 14:55
  • Yea but this is using spring-security dependency library and I don't want to use it=) – BizzyDizzy Nov 23 '15 at 15:09
  • You can get some idea from [here](http://stackoverflow.com/a/33347005/1426227) and from [here](http://stackoverflow.com/a/33302139/1426227). – cassiomolin Nov 23 '15 at 16:19

1 Answers1

1

Some hints and remarks:

  • As REST is stateless I would manage the session on client side instead of persisting a client state on server side.
  • Stateless authentication can be achieved by sending back your BASIC authentication header for every requests/service that you want to be restricted to authenticated users only such as /login and /ping
  • /login service could just throw a WebApplicationException when user is not well authenticated, recognized, in order for your client application to manage it and display an authentication error message to the end user. Then you could use @RolesAllowed('something') annotation with JAAS above your /ping method to restrict access to authenticated user having 'something' role. Thus you would not need to write authentication or authorization code anymore and benefit from an authorization layer in your app.

All this can be achieved on Wildfly with Java EE 7 and without extra libraries.

Rémi Bantos
  • 1,899
  • 14
  • 27
  • Yes for now I used manual login with HttpServletRequest##login and logout. I will however wrap this for a completely stateless user session tracking. Thank you – BizzyDizzy Dec 03 '15 at 04:52