You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jl...@apache.org on 2018/12/12 16:02:32 UTC

[08/11] tomee git commit: TOMEE-2304 Added 401 and 403 test scenarios

TOMEE-2304 Added 401 and 403 test scenarios


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/59c288bb
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/59c288bb
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/59c288bb

Branch: refs/heads/master
Commit: 59c288bb3e5c7b08afe707b970a7d2cad25eed13
Parents: 2e46043
Author: CesarHernandezGt <cf...@gmail.com>
Authored: Tue Dec 11 23:05:16 2018 -0600
Committer: CesarHernandezGt <cf...@gmail.com>
Committed: Tue Dec 11 23:05:16 2018 -0600

----------------------------------------------------------------------
 examples/mp-rest-jwt/README.md                  | 267 ++++++++++++++++++-
 .../org/superbiz/moviefun/rest/MoviesRest.java  |  98 ++-----
 .../java/org/superbiz/moviefun/MoviesTest.java  |  55 ++--
 3 files changed, 319 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/59c288bb/examples/mp-rest-jwt/README.md
----------------------------------------------------------------------
diff --git a/examples/mp-rest-jwt/README.md b/examples/mp-rest-jwt/README.md
index b2dc71f..b4c913f 100644
--- a/examples/mp-rest-jwt/README.md
+++ b/examples/mp-rest-jwt/README.md
@@ -1,4 +1,263 @@
-index-group=Unrevised
-type=page
-status=published
-~~~~~~
+# MP REST JWT
+This is a basic example on how to use MicroProfile JWT in TomEE.
+
+## Run the tests for different scenarios related with JWT validation
+
+    mvn clean test 
+
+## Configuration in TomEE
+
+The class `MoviesMPJWTConfigurationProvider.java` provide to TomEE figuration for JWT validation.
+
+    package org.superbiz.moviefun.rest;
+    
+    import org.apache.tomee.microprofile.jwt.config.JWTAuthContextInfo;
+    
+    import javax.enterprise.context.Dependent;
+    import javax.enterprise.inject.Produces;
+    import java.security.KeyFactory;
+    import java.security.NoSuchAlgorithmException;
+    import java.security.interfaces.RSAPublicKey;
+    import java.security.spec.InvalidKeySpecException;
+    import java.security.spec.X509EncodedKeySpec;
+    import java.util.Base64;
+    import java.util.Optional;
+    
+    @Dependent
+    public class MoviesMPJWTConfigurationProvider {
+    
+        @Produces
+        Optional<JWTAuthContextInfo> getOptionalContextInfo() throws NoSuchAlgorithmException, InvalidKeySpecException {
+            JWTAuthContextInfo contextInfo = new JWTAuthContextInfo();
+    
+            // todo use MP Config to load the configuration
+            contextInfo.setIssuedBy("https://server.example.com");
+    
+            final String pemEncoded = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq" +
+                    "Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR" +
+                    "TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e" +
+                    "UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9" +
+                    "AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn" +
+                    "sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x" +
+                    "nQIDAQAB";
+            byte[] encodedBytes = Base64.getDecoder().decode(pemEncoded);
+    
+            final X509EncodedKeySpec spec = new X509EncodedKeySpec(encodedBytes);
+            final KeyFactory kf = KeyFactory.getInstance("RSA");
+            final RSAPublicKey pk = (RSAPublicKey) kf.generatePublic(spec);
+    
+            contextInfo.setSignerKey(pk);
+    
+            return Optional.of(contextInfo);
+        }
+    
+        @Produces
+        JWTAuthContextInfo getContextInfo() throws InvalidKeySpecException, NoSuchAlgorithmException {
+            return getOptionalContextInfo().get();
+        }
+    }
+
+## Use MicroProfile JWT in TomEE
+
+The JAX-RS resource `MoviesRest.java` contains several endpoint that are secured using the standard 
+annotation `@RolesAllowed`. MicroProfile JWT takes care of performing the validation for incoming
+requests with `Authorization` header providing a signed `Access Token`
+ 
+
+       package org.superbiz.moviefun.rest;
+       
+       import org.superbiz.moviefun.Movie;
+       import org.superbiz.moviefun.MoviesBean;
+       
+       import javax.annotation.security.RolesAllowed;
+       import javax.inject.Inject;
+       import javax.ws.rs.*;
+       import javax.ws.rs.core.MediaType;
+       import java.util.List;
+       
+       @Path("cinema")
+       @Produces(MediaType.APPLICATION_JSON)
+       @Consumes(MediaType.APPLICATION_JSON)
+       public class MoviesRest {
+       
+           @Inject
+           private MoviesBean moviesBean;
+       
+           @GET
+           @Produces(MediaType.TEXT_PLAIN)
+           public String status() {
+               return "ok";
+           }
+       
+           @GET
+           @Path("/movies")
+           @RolesAllowed({"crud", "read-only"})
+           public List<Movie> getListOfMovies() {
+               return moviesBean.getMovies();
+           }
+       
+           @GET
+           @Path("/movies/{id}")
+           @RolesAllowed({"crud", "read-only"})
+           public Movie getMovie(@PathParam("id") int id) {
+               return moviesBean.getMovie(id);
+           }
+       
+           @POST
+           @Path("/movies")
+           @RolesAllowed("crud")
+           public void addMovie(Movie newMovie) {
+               moviesBean.addMovie(newMovie);
+           }
+       
+           @DELETE
+           @Path("/movies/{id}")
+           @RolesAllowed("crud")
+           public void deleteMovie(@PathParam("id") int id) {
+               moviesBean.deleteMovie(id);
+           }
+       
+           @PUT
+           @Path("/movies")
+           @RolesAllowed("crud")
+           public void updateMovie(Movie updatedMovie) {
+               moviesBean.updateMovie(updatedMovie);
+           }
+       
+       }
+
+     @Inject
+     @ConfigProperty(name = "java.runtime.version")
+     private String javaVersion;
+     
+## About the Test architecture
+
+The test cases from this project are builded using Arquillian. The arquillian configuration can be found in
+`src/test/resources/arquillian.xml`
+
+The class `TokenUtils.java` is used during the test to act as an Authorization server who generates `Access Tokens` based
+on the configuration files `privateKey.pem`,`publicKey.pem`,`Token1.json`, and `Token2.json`. 
+
+`nimbus-jose-jwt` is the library used for JWT generation during the testsĀ”.
+
+## Test Scenarios
+
+`MovieTest.java` contains 4 OAuth2 scenarios for different JWT combinations.
+
+    package org.superbiz.moviefun;
+    
+    import org.apache.cxf.feature.LoggingFeature;
+    import org.apache.cxf.jaxrs.client.WebClient;
+    import org.apache.johnzon.jaxrs.JohnzonProvider;
+    import org.jboss.arquillian.container.test.api.Deployment;
+    import org.jboss.arquillian.junit.Arquillian;
+    import org.jboss.arquillian.test.api.ArquillianResource;
+    import org.jboss.shrinkwrap.api.ShrinkWrap;
+    import org.jboss.shrinkwrap.api.asset.StringAsset;
+    import org.jboss.shrinkwrap.api.spec.WebArchive;
+    import org.junit.Test;
+    import org.junit.runner.RunWith;
+    import org.superbiz.moviefun.rest.ApplicationConfig;
+    import org.superbiz.moviefun.rest.MoviesMPJWTConfigurationProvider;
+    import org.superbiz.moviefun.rest.MoviesRest;
+    
+    import javax.ws.rs.core.Response;
+    import java.net.URL;
+    import java.util.Collection;
+    import java.util.HashMap;
+    import java.util.logging.Logger;
+    
+    import static java.util.Collections.singletonList;
+    import static org.junit.Assert.assertTrue;
+    
+    @RunWith(Arquillian.class)
+    public class MoviesTest {
+    
+        @Deployment(testable = false)
+        public static WebArchive createDeployment() {
+            final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war")
+                                                    .addClasses(Movie.class, MoviesBean.class, MoviesTest.class)
+                                                    .addClasses(MoviesRest.class, ApplicationConfig.class)
+                                                    .addClass(MoviesMPJWTConfigurationProvider.class)
+                                                    .addAsWebInfResource(new StringAsset("<beans/>"), "beans.xml");
+    
+            System.out.println(webArchive.toString(true));
+    
+            return webArchive;
+        }
+    
+        @ArquillianResource
+        private URL base;
+    
+    
+        private final static Logger LOGGER = Logger.getLogger(MoviesTest.class.getName());
+    
+        @Test
+        public void movieRestTest() throws Exception {
+    
+            final WebClient webClient = WebClient
+                    .create(base.toExternalForm(), singletonList(new JohnzonProvider<>()),
+                            singletonList(new LoggingFeature()), null);
+    
+    
+            //Testing rest endpoint deployment (GET  without security header)
+            String responsePayload = webClient.reset().path("/rest/cinema/").get(String.class);
+            LOGGER.info("responsePayload = " + responsePayload);
+            assertTrue(responsePayload.equalsIgnoreCase("ok"));
+    
+    
+            //POST (Using token1.json with group of claims: [CRUD])
+            Movie newMovie = new Movie(1, "David Dobkin", "Wedding Crashers");
+            Response response = webClient.reset()
+                                         .path("/rest/cinema/movies")
+                                         .header("Content-Type", "application/json")
+                                         .header("Authorization", "Bearer " + token(1))
+                                         .post(newMovie);
+            LOGGER.info("responseCode = " + response.getStatus());
+            assertTrue(response.getStatus() == 204);
+    
+    
+            //GET movies (Using token1.json with group of claims: [read-only])
+            //This test should be updated to use token2.json once TOMEE- gets resolved.
+            Collection<? extends Movie> movies = webClient
+                    .reset()
+                    .path("/rest/cinema/movies")
+                    .header("Content-Type", "application/json")
+                    .header("Authorization", "Bearer " + token(1))
+                    .getCollection(Movie.class);
+            LOGGER.info(movies.toString());
+            assertTrue(movies.size() == 1);
+    
+    
+            //Should return a 403 since POST require group of claims: [crud] but Token 2 has only [read-only].
+            Movie secondNewMovie = new Movie(2, "Todd Phillips", "Starsky & Hutch");
+            Response responseWithError = webClient.reset()
+                                                  .path("/rest/cinema/movies")
+                                                  .header("Content-Type", "application/json")
+                                                  .header("Authorization", "Bearer " + token(2))
+                                                  .post(secondNewMovie);
+            LOGGER.info("responseCode = " + responseWithError.getStatus());
+            assertTrue(responseWithError.getStatus() == 403);
+    
+    
+            //Should return a 401 since the header Authorization is not part of the POST request.
+            Response responseWith401Error = webClient.reset()
+                                                     .path("/rest/cinema/movies")
+                                                     .header("Content-Type", "application/json")
+                                                     .post(new Movie());
+            LOGGER.info("responseCode = " + responseWith401Error.getStatus());
+            assertTrue(responseWith401Error.getStatus() == 401);
+    
+        }
+    
+    
+        private String token(int token_type) throws Exception {
+            HashMap<String, Long> timeClaims = new HashMap<>();
+            if (token_type == 1) {
+                return TokenUtils.generateTokenString("/Token1.json", null, timeClaims);
+            } else {
+                return TokenUtils.generateTokenString("/Token2.json", null, timeClaims);
+            }
+        }
+    
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/59c288bb/examples/mp-rest-jwt/src/main/java/org/superbiz/moviefun/rest/MoviesRest.java
----------------------------------------------------------------------
diff --git a/examples/mp-rest-jwt/src/main/java/org/superbiz/moviefun/rest/MoviesRest.java b/examples/mp-rest-jwt/src/main/java/org/superbiz/moviefun/rest/MoviesRest.java
index 1ded167..9e67334 100644
--- a/examples/mp-rest-jwt/src/main/java/org/superbiz/moviefun/rest/MoviesRest.java
+++ b/examples/mp-rest-jwt/src/main/java/org/superbiz/moviefun/rest/MoviesRest.java
@@ -39,105 +39,39 @@ public class MoviesRest {
         return "ok";
     }
 
+    @GET
+    @Path("/movies")
+    @RolesAllowed({"crud", "read-only"})
+    public List<Movie> getListOfMovies() {
+        return moviesBean.getMovies();
+    }
+
+    @GET
+    @Path("/movies/{id}")
+    @RolesAllowed({"crud", "read-only"})
+    public Movie getMovie(@PathParam("id") int id) {
+        return moviesBean.getMovie(id);
+    }
+
     @POST
     @Path("/movies")
     @RolesAllowed("crud")
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
     public void addMovie(Movie newMovie) {
         moviesBean.addMovie(newMovie);
     }
 
     @DELETE
     @Path("/movies/{id}")
-    @RolesAllowed("read-only")
+    @RolesAllowed("crud")
     public void deleteMovie(@PathParam("id") int id) {
         moviesBean.deleteMovie(id);
     }
 
     @PUT
     @Path("/movies")
+    @RolesAllowed("crud")
     public void updateMovie(Movie updatedMovie) {
         moviesBean.updateMovie(updatedMovie);
     }
 
-    @GET
-    @Path("/movies/{id}")
-    @RolesAllowed({"read-only","crud"})
-    public Movie getMovie(@PathParam("id") int id) {
-        return moviesBean.getMovie(id);
-    }
-
-    @GET
-    @Path("/movies")
-    @RolesAllowed({"crud", "read-only"})
-    public List<Movie> getListOfMovies() {
-        return moviesBean.getMovies();
-    }
-
-
-//    @Inject
-//    @Claim("raw_token")
-//    private ClaimValue<String> rawToken;
-//
-//    @Inject
-//    @Claim("iss")
-//    private ClaimValue<String> issuer;
-//
-//    @Inject
-//    @Claim("jti")
-//    private ClaimValue<String> jti;
-//
-//    @Inject
-//    private JsonWebToken jwtPrincipal;
-//
-//    @Context
-//    private SecurityContext securityContext;
-//
-//    @GET
-//    @Path("{id}")
-//    public Movie find(@PathParam("id") Long id) {
-//        return service.find(id);
-//    }
-//
-//    @GET
-//    public List<Movie> getMovies(@QueryParam("first") Integer first, @QueryParam("max") Integer max,
-//                                 @QueryParam("field") String field, @QueryParam("searchTerm") String searchTerm) {
-//        return service.getMovies(first, max, field, searchTerm);
-//    }
-//
-//    @POST
-//    @Consumes("application/json")
-//    @RolesAllowed("create")
-//    public Movie addMovie(Movie movie) {
-//        service.addMovie(movie);
-//        return movie;
-//    }
-//
-//    @PUT
-//    @Path("{id}")
-//    @Consumes("application/json")
-//    @RolesAllowed("update")
-//    public Movie editMovie(
-//            @PathParam("id") final long id,
-//            Movie movie
-//    ) {
-//        service.editMovie(movie);
-//        return movie;
-//    }
-//
-//    @DELETE
-//    @Path("{id}")
-//    @RolesAllowed("delete")
-//    public void deleteMovie(@PathParam("id") long id) {
-//        service.deleteMovie(id);
-//    }
-//
-//    @GET
-//    @Path("count")
-//    @Produces(MediaType.TEXT_PLAIN)
-//    public int count(@QueryParam("field") String field, @QueryParam("searchTerm") String searchTerm) {
-//        return service.count(field, searchTerm);
-//    }
-
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/59c288bb/examples/mp-rest-jwt/src/test/java/org/superbiz/moviefun/MoviesTest.java
----------------------------------------------------------------------
diff --git a/examples/mp-rest-jwt/src/test/java/org/superbiz/moviefun/MoviesTest.java b/examples/mp-rest-jwt/src/test/java/org/superbiz/moviefun/MoviesTest.java
index ea622b8..7ba6808 100644
--- a/examples/mp-rest-jwt/src/test/java/org/superbiz/moviefun/MoviesTest.java
+++ b/examples/mp-rest-jwt/src/test/java/org/superbiz/moviefun/MoviesTest.java
@@ -46,10 +46,10 @@ public class MoviesTest {
     @Deployment(testable = false)
     public static WebArchive createDeployment() {
         final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war")
-                .addClasses(Movie.class, MoviesBean.class, MoviesTest.class)
-                .addClasses(MoviesRest.class, ApplicationConfig.class)
-                .addClass(MoviesMPJWTConfigurationProvider.class)
-                .addAsWebInfResource(new StringAsset("<beans/>"), "beans.xml");
+                                                .addClasses(Movie.class, MoviesBean.class, MoviesTest.class)
+                                                .addClasses(MoviesRest.class, ApplicationConfig.class)
+                                                .addClass(MoviesMPJWTConfigurationProvider.class)
+                                                .addAsWebInfResource(new StringAsset("<beans/>"), "beans.xml");
 
         System.out.println(webArchive.toString(true));
 
@@ -66,8 +66,8 @@ public class MoviesTest {
     public void movieRestTest() throws Exception {
 
         final WebClient webClient = WebClient
-                .create(base.toExternalForm(), singletonList(new JohnzonProvider<>()), singletonList(new LoggingFeature()), null);
-
+                .create(base.toExternalForm(), singletonList(new JohnzonProvider<>()),
+                        singletonList(new LoggingFeature()), null);
 
 
         //Testing rest endpoint deployment (GET  without security header)
@@ -75,32 +75,57 @@ public class MoviesTest {
         LOGGER.info("responsePayload = " + responsePayload);
         assertTrue(responsePayload.equalsIgnoreCase("ok"));
 
+
         //POST (Using token1.json with group of claims: [CRUD])
-        Movie newMovie = new Movie(1,"David Dobkin","Wedding Crashers");
-        Response response = webClient.reset().path("/rest/cinema/movies").header("Content-Type","application/json").header("Authorization", "Bearer " + token(1)).post(newMovie);
+        Movie newMovie = new Movie(1, "David Dobkin", "Wedding Crashers");
+        Response response = webClient.reset()
+                                     .path("/rest/cinema/movies")
+                                     .header("Content-Type", "application/json")
+                                     .header("Authorization", "Bearer " + token(1))
+                                     .post(newMovie);
         LOGGER.info("responseCode = " + response.getStatus());
         assertTrue(response.getStatus() == 204);
 
 
-
-        //GET movies (Using token2.json with group of claims: [read-only])
-        final Collection<? extends Movie> movies = webClient
+        //GET movies (Using token1.json with group of claims: [read-only])
+        //This test should be updated to use token2.json once TOMEE- gets resolved.
+        Collection<? extends Movie> movies = webClient
                 .reset()
                 .path("/rest/cinema/movies")
-                .header("Content-Type","application/json")
+                .header("Content-Type", "application/json")
                 .header("Authorization", "Bearer " + token(1))
                 .getCollection(Movie.class);
         LOGGER.info(movies.toString());
         assertTrue(movies.size() == 1);
-    }
 
 
+        //Should return a 403 since POST require group of claims: [crud] but Token 2 has only [read-only].
+        Movie secondNewMovie = new Movie(2, "Todd Phillips", "Starsky & Hutch");
+        Response responseWithError = webClient.reset()
+                                              .path("/rest/cinema/movies")
+                                              .header("Content-Type", "application/json")
+                                              .header("Authorization", "Bearer " + token(2))
+                                              .post(secondNewMovie);
+        LOGGER.info("responseCode = " + responseWithError.getStatus());
+        assertTrue(responseWithError.getStatus() == 403);
+
+
+        //Should return a 401 since the header Authorization is not part of the POST request.
+        Response responseWith401Error = webClient.reset()
+                                                 .path("/rest/cinema/movies")
+                                                 .header("Content-Type", "application/json")
+                                                 .post(new Movie());
+        LOGGER.info("responseCode = " + responseWith401Error.getStatus());
+        assertTrue(responseWith401Error.getStatus() == 401);
+
+    }
+
 
     private String token(int token_type) throws Exception {
         HashMap<String, Long> timeClaims = new HashMap<>();
-        if(token_type==1){
+        if (token_type == 1) {
             return TokenUtils.generateTokenString("/Token1.json", null, timeClaims);
-        }else{
+        } else {
             return TokenUtils.generateTokenString("/Token2.json", null, timeClaims);
         }
     }