15

I am using JBoss AS and JAX-RS for creating REST endpoints.

Lets say my class looks like

@Path("/users")
public class UserResource {


  @GET
  public Response getAccount() {
    return "hello";
  }
}

Now getAccount is not authenticated at the moment

Wanted
- I would like to add authentication so that when code hits getAccount the user is authenticated
- I would like the authentication to be driven by annotations instead of XML configurations, if at all possible
- I would like to do the database comparison to see if the user is valid

Problem
- I have never done that so I have no idea how to implement it
- I have googled around a lot and found Jersey examples

UPDATE
- I would like to send authentication credentials with each request and not creating any session

Please guide me with one simple working example and I would try to extend from there

daydreamer
  • 87,243
  • 191
  • 450
  • 722
  • Are you going to require the authentication credentials get passed in with every request, or are you going to allow the creation of a session? – thatidiotguy Aug 06 '13 at 17:00
  • I just updated my question, I would like to send credentials with each request and not create any sessions – daydreamer Aug 06 '13 at 17:02
  • I have implemented the solution Please see my answer at http://stackoverflow.com/questions/18345600/how-to-intercept-rest-endpoint-to-receive-all-headers?answertab=oldest#tab-top – daydreamer Aug 21 '13 at 16:22

2 Answers2

15

You need is a Stateless Spring Security configuration in front of your JAX RS end points. I have addressed exact problem you are trying to solve but I don't have my own code to share..

Here is one project which has done the exact thing you are asking, Some wise man has done it all for you ;)

https://github.com/philipsorst/angular-rest-springsecurity

What is the magic ?

  1. You have one unprotected URL which does the Authentication, and set the user roles as well..
  2. Then you return some kind of Token, put it some where in cache which will be expected on every subsequent call..
  3. Upon new request on other protected resources, you will check if the Token is present in your cache/session store ( you need some mechanism to keep track of valid tokens )
  4. If token is resent and valid, you do the programmatic Log-in in Spring Security which ensures that you can use all the Security features spring provides, ( Annotations, JSTL Tags etc.. ) !
  5. Once passed token validation you will get the logged in user details in your controllers ( aka JAX RS resources ) to deal with security further..
  6. If the token was not valid or not present , it would be trapped by failure end point which would return appropriate response ( 401 )

Refer Following Link To Understand How Stateless Spring Security is configured.., https://github.com/philipsorst/angular-rest-springsecurity/blob/master/src/main/resources/context.xml

See how a user is validated for the first time and a token is generated.. https://github.com/philipsorst/angular-rest-springsecurity/blob/master/src/main/java/net/dontdrinkandroot/example/angularrestspringsecurity/rest/resources/UserResource.java

Here is the class where programmatic login is performed on every request after token check.. https://github.com/philipsorst/angular-rest-springsecurity/blob/master/src/main/java/net/dontdrinkandroot/example/angularrestspringsecurity/rest/AuthenticationTokenProcessingFilter.java

Rakesh Waghela
  • 2,227
  • 2
  • 26
  • 46
  • This helped me as well. As I needed to check a few details in different manner, I ended up with "just another demo". While the basics are very similar (can't deny the inspiration started here), I dropped UI and JPA/DB and focused on Spring Security more. Result is [here](https://github.com/virgo47/restful-spring-security), it's commented, Gradle-based, contains test.sh based on curl. And I wrote a [blog post](http://virgo47.wordpress.com/2014/07/27/restful-spring-security-with-authentication-token/) about this topic as well with couple of sequence diagrams. Should be helpful. – virgo47 Jul 27 '14 at 22:08
  • 1
    Hey rakesh, I have checked the angular-rest-springsecurity project on github, i have one question, though all the security related issues are taken care with authorization in picture, but when i refresh the browser once the user is `authenticated` the control seems to be redirected to the login page, even when i just login and click refresh.... do u have any idea about this..? – Amit May 14 '15 at 05:17
11

I solved this with following code.

note Token mechanism will be updated once I do that

I have solved this by modifying the interceptor I have, the following is code

Annotation

@Inherited
@InterceptorBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityChecked {

}

Resource Class

public class SecureResource {

    @GET
    @SecurityChecked
    public Response getUser() {
        return Response.ok("authenticated successfully!").build();
    }
}

Interceptor class

@Interceptor
@Provider
@ServerInterceptor
@SecurityChecked
public class SecurityCheckInterceptor implements PreProcessInterceptor, AcceptedByMethod {
    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityCheckInterceptor.class);

    @Nullable
    @Override
    public ServerResponse preProcess(final HttpRequest request, final ResourceMethod method) throws Failure, WebApplicationException {
        final List<String> authToken = request.getHttpHeaders().getRequestHeader("X-AUTH");

        if (authToken == null || !isValidToken(authToken.get(0))) {
            final ServerResponse serverResponse = new ServerResponse();
            serverResponse.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
            return serverResponse;
        }

        return null;
    }

    private static boolean isValidToken(@Nonnull final String authToken) {
        LOGGER.info("validating token: " + authToken);
        return true;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public boolean accept(final Class declaring, final Method method) {
        // return declaring.isAnnotationPresent(SecurityChecked.class); // if annotation on class
        return method.isAnnotationPresent(SecurityChecked.class);
    }
}

and then I run my Integration tests by deploying the resource class in JBoss and issuing following commands on command-line

curl --header 'X-AUTH: 1a629d035831feadOOO4uFReLyEW8aTmrCS' http://localhost:8080/market-1.0-SNAPSHOT/rest/login
curl --header 'InvalidHeader: InvalidHeaderValue' http://localhost:8080/market-1.0-SNAPSHOT/rest/login
daydreamer
  • 87,243
  • 191
  • 450
  • 722