From 6fcafa431535e0d2ff25606b57353726cf09acd4 Mon Sep 17 00:00:00 2001 From: cotnic Date: Sat, 29 Dec 2018 09:11:09 +0100 Subject: [PATCH 1/3] created REST service. TODO: Implement the JWT JWK functionalities --- examples/mp-rest-jwt-jwk/README.adoc | 0 .../java/org/superbiz/entity/Product.java | 59 +++++++++++++ .../java/org/superbiz/rest/ProductRest.java | 77 +++++++++++++++++ .../org/superbiz/rest/RestApplication.java | 28 ++++++ .../org/superbiz/service/ProductService.java | 54 ++++++++++++ .../java/org/superbiz/rest/ProductsTest.java | 86 +++++++++++++++++++ 6 files changed, 304 insertions(+) create mode 100644 examples/mp-rest-jwt-jwk/README.adoc create mode 100644 examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/entity/Product.java create mode 100644 examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java create mode 100644 examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/RestApplication.java create mode 100644 examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java create mode 100644 examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java diff --git a/examples/mp-rest-jwt-jwk/README.adoc b/examples/mp-rest-jwt-jwk/README.adoc new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/entity/Product.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/entity/Product.java new file mode 100644 index 00000000000..ae59578a7b7 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/entity/Product.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.entity; + +import java.math.BigDecimal; + +public class Product { + + private Integer id; + private String name; + private BigDecimal price; + private Integer stock; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public Integer getStock() { + return stock; + } + + public void setStock(Integer stock) { + this.stock = stock; + } +} diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java new file mode 100644 index 00000000000..499f634e404 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.rest; + + +import org.superbiz.entity.Product; +import org.superbiz.service.ProductService; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; + +@Path("store") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ProductRest { + + @Inject + private ProductService productService; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String status() { + return "running"; + } + + @GET + @Path("/products") + @RolesAllowed({"guest", "admin"}) + public List getListOfMovies() { + return productService.getProducts(); + } + + @GET + @Path("/products/{id}") + @RolesAllowed({"guest", "admin"}) + public Product getMovie(@PathParam("id") int id) { + return productService.getProduct(id); + } + + @POST + @Path("/products") + @RolesAllowed({"admin"}) + public void addMovie(Product product) { + productService.addProduct(product); + } + + @DELETE + @Path("/products/{id}") + @RolesAllowed({"admin"}) + public void deleteMovie(@PathParam("id") int id) { + productService.deleteProduct(id); + } + + @PUT + @Path("/products") + @RolesAllowed({"admin"}) + public void updateMovie(Product product) { + productService.updateProduct(product); + } +} diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/RestApplication.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/RestApplication.java new file mode 100644 index 00000000000..b20d999b9f8 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/RestApplication.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.rest; + + +import org.eclipse.microprofile.auth.LoginConfig; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/rest") +@LoginConfig(authMethod = "MP-JWT") +public class RestApplication extends Application { +} diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java new file mode 100644 index 00000000000..698c507d151 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.service; + +import org.superbiz.entity.Product; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import java.util.*; + +@ApplicationScoped +public class ProductService { + + private Map productsInStore; + + @PostConstruct + public void ProductService() { + productsInStore = new HashMap(); + } + + public List getProducts() { + return new ArrayList<>(productsInStore.values()); + } + + public Product getProduct(int id) { + return productsInStore.get(id); + } + + public void addProduct(Product product) { + productsInStore.put(product.getId(), product); + } + + public void deleteProduct(int id) { + productsInStore.remove(id); + } + + public void updateProduct(Product product) { + productsInStore.put(product.getId(), product); + } +} diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java new file mode 100644 index 00000000000..c8ceb6fb6d6 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java @@ -0,0 +1,86 @@ +package org.superbiz.rest; + +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.entity.Product; +import org.superbiz.service.ProductService; + +import java.net.URL; +import java.util.logging.Logger; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertTrue; + +@RunWith(Arquillian.class) +public class ProductsTest { + + private final static Logger LOGGER = Logger.getLogger(ProductsTest.class.getName()); + @ArquillianResource + private URL base; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war") + .addClasses(Product.class, ProductService.class, ProductsTest.class) + .addClasses(ProductRest.class, RestApplication.class) +// .addClass(MoviesMPJWTConfigurationProvider.class) + .addAsWebInfResource(new StringAsset(""), "beans.xml"); + + System.out.println(webArchive.toString(true)); + + return webArchive; + } + + @Test + public void runningOfProductsApiTest() { + + 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/store/").get(String.class); + LOGGER.info("responsePayload = " + responsePayload); + assertTrue(responsePayload.equalsIgnoreCase("running")); + } + + @Test + public void createProductTest() { + + throw new RuntimeException("TODO Implement!"); + } + + @Test + public void getAllProductsTest() { + + throw new RuntimeException("TODO Implement!"); + } + + @Test + public void getProductWithIdTest() { + + throw new RuntimeException("TODO Implement!"); + } + + @Test + public void updateProductTest() { + + throw new RuntimeException("TODO Implement!"); + } + + @Test + public void deleteProductTest() { + + throw new RuntimeException("TODO Implement!"); + } +} From d267983ae3c2c9ee1805a01016829f2ea7d36192 Mon Sep 17 00:00:00 2001 From: cotnic Date: Wed, 2 Jan 2019 11:13:25 +0100 Subject: [PATCH 2/3] TOMEE-2332: example for JWKs usage in MicroProfile JWT with TomEE --- examples/mp-rest-jwt-jwk/README.adoc | 76 +++++++ examples/mp-rest-jwt-jwk/pom.xml | 215 ++++++++++++++++++ .../java/org/superbiz/rest/ProductRest.java | 24 +- .../org/superbiz/service/ProductService.java | 4 +- .../META-INF/microprofile-config.properties | 2 + .../src/main/resources/jwks.json | 28 +++ .../org/superbiz/rest/KeyGeneratorUtil.java | 42 ++++ .../org/superbiz/rest/ProductRestClient.java | 57 +++++ .../java/org/superbiz/rest/ProductsTest.java | 98 ++++---- .../java/org/superbiz/rest/TokenUtils.java | 84 +++++++ .../META-INF/microprofile-config.properties | 3 + .../src/test/resources/arquillian.xml | 35 +++ .../src/test/resources/jwt-alice.json | 10 + .../src/test/resources/jwt-john.json | 10 + .../src/test/resources/privateKey002.pem | 24 ++ .../src/test/resources/privateKey004.pem | 24 ++ 16 files changed, 684 insertions(+), 52 deletions(-) create mode 100644 examples/mp-rest-jwt-jwk/pom.xml create mode 100644 examples/mp-rest-jwt-jwk/src/main/resources/META-INF/microprofile-config.properties create mode 100644 examples/mp-rest-jwt-jwk/src/main/resources/jwks.json create mode 100644 examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java create mode 100644 examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductRestClient.java create mode 100644 examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/TokenUtils.java create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/META-INF/microprofile-config.properties create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/arquillian.xml create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/jwt-alice.json create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/jwt-john.json create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/privateKey002.pem create mode 100644 examples/mp-rest-jwt-jwk/src/test/resources/privateKey004.pem diff --git a/examples/mp-rest-jwt-jwk/README.adoc b/examples/mp-rest-jwt-jwk/README.adoc index e69de29bb2d..08e9969b4b4 100644 --- a/examples/mp-rest-jwt-jwk/README.adoc +++ b/examples/mp-rest-jwt-jwk/README.adoc @@ -0,0 +1,76 @@ += MicroProfile JWT JWKs +:index-group: MicroProfile +:jbake-type: page +:jbake-status: published + +This is an example on how to use MicroProfile JWT in TomEE by using the +public key as JWKs. + +== Run the application: + +[source, bash] +---- +mvn clean install tomee:run +---- + +This example is a CRUD application for products available. + +== Requirments and configuration + +For usage of MicroProfile JWT we have to change the following to our +project: + +[arabic] +. Add the dependency to our `pom.xml` file: ++ +.... + + org.eclipse.microprofile.jwt + microprofile-jwt-auth-api + ${mp-jwt.version} + provided + +.... +. Annotate our `Application.class` with `@LoginConfig(authMethod = "MP-JWT")` + +. Provide public and private key for authentication. And specify the location of the public key and the issuer in our +`microprofile-config.properties` file. ++ +[source,properties] +---- +mp.jwt.verify.publickey.location=/jwks.pem +mp.jwt.verify.issuer=https://example.com +---- + +. Define `@RolesAllowed()` on the endpoints we want to protect. + +== About the application architecture + +The application enables us to manipulate and view products with specific users. We have two users +`Alice Wonder` and `John Doe`. They can read, create, edit and delete specific entries. + +`jwt-john.json` + +[source,json] +---- +{ + "iss": "https://example.com", + "sub": "24400320", + "name": "John Doe", + "upn": "john.doe@example.com", + "preferred_username": "john", + "groups": [ + "guest", "admin" + ] +} +---- + +== Access the endpoints with JWT token + +We access endpoints from our test class by creating a `JWT` with the help of +our `TokenUtils.generateJWTString(String jsonResource, String keyId)` which signs our user +data in json format with the help of our `src/test/resources/{keyId}` key. + +We can also generate new `privateKey.pem` and `publicKey.pem` with the +`GenerateKeyUtils.generateKeyPair(String keyAlgorithm, int keySize)` method which +then creates the `publicKey.pem` also in `JWK` format. \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/pom.xml b/examples/mp-rest-jwt-jwk/pom.xml new file mode 100644 index 00000000000..8a2e02553a5 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/pom.xml @@ -0,0 +1,215 @@ + + + + 4.0.0 + + org.superbiz + mp-rest-jwt-jwk + 8.0.0-SNAPSHOT + war + OpenEJB :: Examples :: MP REST JWT JWK + + + UTF-8 + 8.0.0-SNAPSHOT + 2.0.0 + 1.1 + 1.1 + + + + install + phonestore + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + false + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.tomee.maven + tomee-maven-plugin + ${tomee.version} + + microprofile + -Xmx512m -XX:PermSize=256m + ${project.basedir}/src/main/tomee/ + + + + + + + + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-bom + ${version.shrinkwrap.resolver} + import + pom + + + + org.jboss.arquillian + arquillian-bom + 1.0.3.Final + import + pom + + + + + + + + org.apache.tomee + javaee-api + 8.0 + provided + + + + org.eclipse.microprofile.jwt + microprofile-jwt-auth-api + ${mp-jwt.version} + provided + + + org.eclipse.microprofile.rest.client + microprofile-rest-client-api + ${mp-rest-client.version} + provided + + + com.nimbusds + nimbus-jose-jwt + 4.23 + test + + + + junit + junit + 4.12 + test + + + + + org.apache.tomee + openejb-cxf-rs + ${tomee.version} + test + + + + org.apache.tomee + openejb-core + ${tomee.version} + test + + + commons-lang + commons-lang + 2.4 + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-depchain + pom + test + + + + + + arquillian-tomee-remote + + true + + + + org.apache.tomee + arquillian-tomee-remote + ${tomee.version} + test + + + org.apache.tomee + apache-tomee + ${tomee.version} + zip + microprofile + test + + + org.apache.tomee + mp-jwt + ${tomee.version} + provided + + + + + + + + + localhost + file://${basedir}/target/repo/ + + + localhost + file://${basedir}/target/snapshot-repo/ + + + diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java index 499f634e404..8b4ba748c5c 100644 --- a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/rest/ProductRest.java @@ -24,6 +24,7 @@ import javax.inject.Inject; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.util.List; @Path("store") @@ -43,35 +44,46 @@ public String status() { @GET @Path("/products") @RolesAllowed({"guest", "admin"}) - public List getListOfMovies() { + public List getListOfProducts() { return productService.getProducts(); } @GET @Path("/products/{id}") @RolesAllowed({"guest", "admin"}) - public Product getMovie(@PathParam("id") int id) { + public Product getProduct(@PathParam("id") int id) { return productService.getProduct(id); } @POST @Path("/products") @RolesAllowed({"admin"}) - public void addMovie(Product product) { - productService.addProduct(product); + public Response addProduct(Product product) { + return Response.status(Response.Status.CREATED) + .entity(productService.addProduct(product)) + .build(); } @DELETE @Path("/products/{id}") @RolesAllowed({"admin"}) - public void deleteMovie(@PathParam("id") int id) { + public Response deleteProduct(@PathParam("id") int id) { productService.deleteProduct(id); + + return Response + .status(Response.Status.NO_CONTENT) + .build(); } @PUT @Path("/products") @RolesAllowed({"admin"}) - public void updateMovie(Product product) { + public Response updateProduct(Product product) { productService.updateProduct(product); + + return Response + .status(Response.Status.OK) + .entity(product) + .build(); } } diff --git a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java index 698c507d151..ab917a323dd 100644 --- a/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java +++ b/examples/mp-rest-jwt-jwk/src/main/java/org/superbiz/service/ProductService.java @@ -40,8 +40,10 @@ public Product getProduct(int id) { return productsInStore.get(id); } - public void addProduct(Product product) { + public Product addProduct(Product product) { productsInStore.put(product.getId(), product); + + return product; } public void deleteProduct(int id) { diff --git a/examples/mp-rest-jwt-jwk/src/main/resources/META-INF/microprofile-config.properties b/examples/mp-rest-jwt-jwk/src/main/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..43e9a863954 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1,2 @@ +mp.jwt.verify.publickey.location=/jwks.json +mp.jwt.verify.issuer=https://example.com \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/main/resources/jwks.json b/examples/mp-rest-jwt-jwk/src/main/resources/jwks.json new file mode 100644 index 00000000000..cd5bb2f4a0f --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/main/resources/jwks.json @@ -0,0 +1,28 @@ +{ + "keys": [ + { + "kid": "privateKey001.pem", + "kty": "RSA", + "e": "AQAB", + "n": "wHV0xEZDVMgVGxH8cdQqncMEg72fUQfKBwO-wVJSv1xYLBoPDK228oGHrPLbLGGW9QrXqekVoGlyld5j9xT74iMyzw3onyQywL5cTfxWNxzowTbQQQUSJ5kNF130K5tyJAqUMRZ3L69r1_pHjtKSxZcGXdb_w8L7qcvQ7kNoCRR0erLBTkDgM2hA2hYf8QxKc_ua8XP8V5Eqn4Elo2EILjVzV_X3GArU00Ets15rLRc8KK_99sQFKrgB2IFW-LfUQD7pvOXyIaF560DF57kdf2ZMFNQpYa3wphHgC8EVgblaMG-1cvda-ZBtcF0Q-efSxk2SQJyyETvEXq0SKcXjww" + }, + { + "kid": "privateKey002.pem", + "kty": "RSA", + "e": "AQAB", + "n": "oodvcIxwKkxfFP8KwQV9Upxl8tqTmPOBFVu1In2a9dOfREZep5bJCwJcSu5wZ1IpE_e7vMi8PktXF2B0r0yHmelP98hcFHFzeNxvgXmMWpzPx84FZXP1EgCBP5DzGCvC-PBvMfYMM81UNESOyCD4wF_JnnuIxFDf0JUlQrF81DjuQzspK3j7ENRc8QR0PLKbD8Dq7T1RRQoT5F5pkXgCMreaib_rgL-3snBbTjjp8UyhfLyuEJrJX_ee_5T4WS7xU42BxKv_jJmHixmv9EHBMOVKqXzLgFlF0tAuI_qHGl0HaRNencTE2O3C_b56VHXp1sH6RM65m2MIciDqKeGGUw" + }, + { + "kid": "privateKey003.pem", + "kty": "RSA", + "e": "AQAB", + "n": "hrPRLyhDpMGU-RgTFwEeYoaoOTSJIA1hMjj0CoBxC6sZOu5X3gHC4luytIvwYDOEcp9L_G5JLPgJrOs-IHn8SK4IPacdEjz_yua18984TnH-Jy8k2T_Clf2gGgdeu3MG2byBmnU3rxGKIayHGp9RAXPYlJZOJppo6JA7e3uBEkH9nJMumNEpFABgBKRimg8MEnBaQtsEUkYM8nFFtzn9Qahvy9c3scTdwxCos0JdERlsK6ImhqCDSsicDbOkeE7sAzVRAnpDCr9_j0OEh2-z6gH9aLxNNTuG7vHCf-UzYIZpHjG3ezSLhiWpFsXWokc8tCtM7alZap9pbzh2YU5j0w" + }, + { + "kid": "privateKey004.pem", + "kty": "RSA", + "e": "AQAB", + "n": "iNaojcX7ASG-5-ex2u4H72nvisfr-tydFVHrkocLdDUa_Uy2QXvqB-wp14C1mJdrWnAB2oqlY8RuuachdFg7FgDtgm1XdBv4ORqnF6ljrnYrbIcAtig1il1K-8JQZSy9WNMvBF9LMGjY3Y3G2hw3bsit0-lJQaP7m_ZmwSwIc6LSpP3wLBw2u3I5IO05BTbZstV3UcDRllm_cqU_0gZJEy6MsNbQiXrHX5bN_xsw256Cr7sPsSuTmSVx5M8tOcwFOKmvklDbnDqidMw7un4IvcMt8wpinGImnKi4AiiBtDRBGlgj879iNyJa1xKYmHNe1WkJhjwQZ_ZgbZiCBAAghw" + } + ] +} \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java new file mode 100644 index 00000000000..e9f9949a228 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java @@ -0,0 +1,42 @@ +package org.superbiz.rest; + +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.util.Base64; +import java.util.UUID; + +public class KeyGeneratorUtil { + + public static void main(String[] args) throws NoSuchAlgorithmException { + generateKeyPair("RSA", 2048); + } + + public static void generateKeyPair(String keyAlgorithm, int keySize) throws NoSuchAlgorithmException { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); // RSA + kpg.initialize(keySize); // 2048 + KeyPair kp = kpg.generateKeyPair(); + + System.out.println("-----BEGIN PRIVATE KEY-----"); + System.out.println(Base64.getMimeEncoder().encodeToString(kp.getPrivate().getEncoded())); + System.out.println("-----END PRIVATE KEY-----"); + System.out.println("-----BEGIN PUBLIC KEY-----"); + System.out.println(Base64.getMimeEncoder().encodeToString(kp.getPublic().getEncoded())); + System.out.println("-----END PUBLIC KEY-----"); + + RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic(); + + RSAKey jwk = new RSAKey.Builder(publicKey) + .privateKey((RSAPrivateKey) kp.getPrivate()) + .keyUse(KeyUse.SIGNATURE) + .keyID(UUID.randomUUID().toString()) + .build(); + + System.out.println(jwk.toJSONObject().toJSONString()); + } +} diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductRestClient.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductRestClient.java new file mode 100644 index 00000000000..97b93ebdd12 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductRestClient.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.rest; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import org.superbiz.entity.Product; + +import javax.enterprise.context.Dependent; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +@Dependent +@RegisterRestClient +@Path("/test/rest/store") +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +public interface ProductRestClient { + + @GET + String status(); + + @GET + @Path("/products/{id}") + Response getProduct(@HeaderParam("Authorization") String authHeaderValue, @PathParam("id") int id); + + @GET + @Path("/products") + List getProductList(@HeaderParam("Authorization") String authHeaderValue); + + @POST + @Path("/products") + Response addProduct(@HeaderParam("Authorization") String authHeaderValue, Product newProduct); + + @PUT + @Path("/products") + Response updateProduct(@HeaderParam("Authorization") String authHeaderValue, Product updatedProduct); + + @DELETE + @Path("/products/{id}") + Response deleteProduct(@HeaderParam("Authorization") String authHeaderValue, @PathParam("id") int id); +} diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java index c8ceb6fb6d6..2eb6dfb8579 100644 --- a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java @@ -1,11 +1,8 @@ package org.superbiz.rest; -import org.apache.cxf.feature.LoggingFeature; -import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.johnzon.jaxrs.JohnzonProvider; +import org.eclipse.microprofile.rest.client.inject.RestClient; 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; @@ -14,73 +11,84 @@ import org.superbiz.entity.Product; import org.superbiz.service.ProductService; -import java.net.URL; -import java.util.logging.Logger; +import javax.inject.Inject; +import javax.ws.rs.core.Response; +import java.math.BigDecimal; +import java.util.List; -import static java.util.Collections.singletonList; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; @RunWith(Arquillian.class) public class ProductsTest { - private final static Logger LOGGER = Logger.getLogger(ProductsTest.class.getName()); - @ArquillianResource - private URL base; + @Inject + @RestClient + private ProductRestClient productRestClient; - @Deployment(testable = false) + @Deployment() public static WebArchive createDeployment() { final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war") - .addClasses(Product.class, ProductService.class, ProductsTest.class) .addClasses(ProductRest.class, RestApplication.class) -// .addClass(MoviesMPJWTConfigurationProvider.class) - .addAsWebInfResource(new StringAsset(""), "beans.xml"); - - System.out.println(webArchive.toString(true)); - + .addClasses(Product.class) + .addClass(ProductService.class) + .addClasses(ProductRestClient.class, TokenUtils.class) + .addPackages(true, "com.nimbusds", "net.minidev.json") + .addAsWebInfResource(new StringAsset(""), "beans.xml") + .addAsResource("META-INF/microprofile-config.properties") + .addAsResource("jwt-john.json") + .addAsResource("privateKey002.pem") + .addAsResource("jwks.json"); return webArchive; } @Test public void runningOfProductsApiTest() { - 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/store/").get(String.class); - LOGGER.info("responsePayload = " + responsePayload); - assertTrue(responsePayload.equalsIgnoreCase("running")); + assertEquals("running", productRestClient.status()); } @Test - public void createProductTest() { + public void shouldMakeProductFlow() throws Exception { + Product productHuawei = new Product(); + productHuawei.setId(1); + productHuawei.setName("Huawei P20 Pro"); + productHuawei.setPrice(new BigDecimal(820.41)); + productHuawei.setStock(6); - throw new RuntimeException("TODO Implement!"); - } + int statusCode = productRestClient.addProduct("Bearer " + createJwtToken(), productHuawei).getStatus(); - @Test - public void getAllProductsTest() { + assertEquals(Response.Status.CREATED.getStatusCode(), statusCode); - throw new RuntimeException("TODO Implement!"); - } - @Test - public void getProductWithIdTest() { + Product productSamsung = new Product(); + productSamsung.setId(2); + productSamsung.setName("Samsung S9"); + productSamsung.setPrice(new BigDecimal(844.42)); + productSamsung.setStock(2); - throw new RuntimeException("TODO Implement!"); - } + statusCode = productRestClient.addProduct("Bearer " + createJwtToken(), productSamsung).getStatus(); - @Test - public void updateProductTest() { + assertEquals(Response.Status.CREATED.getStatusCode(), statusCode); - throw new RuntimeException("TODO Implement!"); - } + productSamsung.setStock(5); - @Test - public void deleteProductTest() { + Response response = productRestClient.updateProduct("Bearer " + createJwtToken(), productSamsung); + + Product updatedProduct = response.readEntity(Product.class); + + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(5, updatedProduct.getStock().intValue()); + + List products = productRestClient.getProductList("Bearer " + createJwtToken()); + + assertEquals(2, products.size()); + + statusCode = productRestClient.deleteProduct("Bearer " + createJwtToken(), 2).getStatus(); + + assertEquals(Response.Status.NO_CONTENT.getStatusCode(), statusCode); + } - throw new RuntimeException("TODO Implement!"); + private String createJwtToken() throws Exception { + return TokenUtils.generateJWTString("jwt-john.json", "privateKey002.pem"); } } diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/TokenUtils.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/TokenUtils.java new file mode 100644 index 00000000000..7f8e365ff4e --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/TokenUtils.java @@ -0,0 +1,84 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.rest; + +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jwt.SignedJWT; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import org.eclipse.microprofile.jwt.Claims; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; + +import static com.nimbusds.jose.JOSEObjectType.JWT; +import static com.nimbusds.jose.JWSAlgorithm.RS256; +import static com.nimbusds.jwt.JWTClaimsSet.parse; +import static java.lang.Thread.currentThread; +import static net.minidev.json.parser.JSONParser.DEFAULT_PERMISSIVE_MODE; + +public class TokenUtils { + + + public static String generateJWTString(String jsonResource, String keyId) throws Exception { + byte[] byteBuffer = new byte[16384]; + currentThread().getContextClassLoader() + .getResource(jsonResource) + .openStream() + .read(byteBuffer); + + JSONParser parser = new JSONParser(DEFAULT_PERMISSIVE_MODE); + JSONObject jwtJson = (JSONObject) parser.parse(byteBuffer); + + long currentTimeInSecs = (System.currentTimeMillis() / 1000); + long expirationTime = currentTimeInSecs + 1000; + + jwtJson.put(Claims.iat.name(), currentTimeInSecs); + jwtJson.put(Claims.auth_time.name(), currentTimeInSecs); + jwtJson.put(Claims.exp.name(), expirationTime); + + SignedJWT signedJWT = new SignedJWT(new JWSHeader + .Builder(RS256) + .keyID(keyId) // /privateKey002.pem + .type(JWT) + .build(), parse(jwtJson)); + + signedJWT.sign(new RSASSASigner(readPrivateKey(keyId))); + + return signedJWT.serialize(); + } + + public static PrivateKey readPrivateKey(String resourceName) throws Exception { + byte[] byteBuffer = new byte[16384]; + int length = currentThread().getContextClassLoader() + .getResource(resourceName) + .openStream() + .read(byteBuffer); + + String key = new String(byteBuffer, 0, length).replaceAll("-----BEGIN (.*)-----", "") + .replaceAll("-----END (.*)----", "") + .replaceAll("\r\n", "") + .replaceAll("\n", "") + .trim(); + + return KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key))); + } +} diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/META-INF/microprofile-config.properties b/examples/mp-rest-jwt-jwk/src/test/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..d16e2e19d60 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/META-INF/microprofile-config.properties @@ -0,0 +1,3 @@ +org.superbiz.rest.ProductRestClient/mp-rest/url=http://localhost:4444 +mp.jwt.verify.publickey.location=/jwks.json +mp.jwt.verify.issuer=https://example.com \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/arquillian.xml b/examples/mp-rest-jwt-jwk/src/test/resources/arquillian.xml new file mode 100644 index 00000000000..31daf70aca4 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/arquillian.xml @@ -0,0 +1,35 @@ + + + + + + + -1 + 4444 + -1 + -1 + microprofile + true + true + target/server + target/arquillian + + + \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/jwt-alice.json b/examples/mp-rest-jwt-jwk/src/test/resources/jwt-alice.json new file mode 100644 index 00000000000..efc8c9f97b9 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/jwt-alice.json @@ -0,0 +1,10 @@ +{ + "iss": "https://example.com", + "sub": "24400623", + "name": "Alice Wonder", + "upn": "alice.wonder@example.com", + "preferred_username": "alice", + "groups": [ + "guest" + ] +} \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/jwt-john.json b/examples/mp-rest-jwt-jwk/src/test/resources/jwt-john.json new file mode 100644 index 00000000000..6aa3bce3543 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/jwt-john.json @@ -0,0 +1,10 @@ +{ + "iss": "https://example.com", + "sub": "24400320", + "name": "John Doe", + "upn": "john.doe@example.com", + "preferred_username": "john", + "groups": [ + "guest", "admin" + ] +} \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/privateKey002.pem b/examples/mp-rest-jwt-jwk/src/test/resources/privateKey002.pem new file mode 100644 index 00000000000..802446d23c8 --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/privateKey002.pem @@ -0,0 +1,24 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCih29wjHAqTF8U/wrBBX1SnGXy +2pOY84EVW7UifZr1059ERl6nlskLAlxK7nBnUikT97u8yLw+S1cXYHSvTIeZ6U/3yFwUcXN43G+B +eYxanM/HzgVlc/USAIE/kPMYK8L48G8x9gwzzVQ0RI7IIPjAX8mee4jEUN/QlSVCsXzUOO5DOykr +ePsQ1FzxBHQ8spsPwOrtPVFFChPkXmmReAIyt5qJv+uAv7eycFtOOOnxTKF8vK4Qmslf957/lPhZ +LvFTjYHEq/+MmYeLGa/0QcEw5UqpfMuAWUXS0C4j+ocaXQdpE16dxMTY7cL9vnpUdenWwfpEzrmb +YwhyIOop4YZTAgMBAAECggEAd2SEYapY70mhA1yDet3cfSY04hzdFhuy9Iyk2Exq3DD0K4SCHhxv +XW4DfGwCGHRLhsaSnBDd7+kKdjq+HNRcPJ0eyIff1Iiu6dcM9pDioOHW5REb97YiDnJef+KsIVJs +bNC67nmv5xHrzGWcebl24mK7Sne3NXevopsdfwvBBmgFhSi1psnSdmabucT/5ibiG9W6U0/EaUO/ +8qaavClhv1SH8gsoUBXvknrpS5Wr+01Qmre80NXpBd6JVloS32pwnBmWEhsjBUEJMNVM7Hl4Xxh0 +iZBmnqCJqVBGEGYwBS/YlPF0nNcUm4VEorycnuqe3Y6vP1jP+zMPZYAXs0CBkQKBgQD75U/iBnAS +LePvbuXjoFxZ2CWJS3ukwyUyfJG7z95gn603X4h024t9IIUuH7isWQPpMQ13Rg7MdHzq6+Loqhon +mBwGYeCHlhRTsmcYORQrgUjcNdaWOmAELYv+V0G9Vz9X/HDUvAczyVExXo4Pjgv7me1rr6vCmJ6N +KuoGcEArWQKBgQClLV0jFYgj1x+SbPUNkMyUBHK/47bWmbnooTsWzfZxcSU5KLNb7yygaIvGzSSm +LJJFnlJeJ0597xpVW2ex6Eeg4AK5GNflGNrlmE+SWIKJq7bZx6fChDK3OK77MK8bql566PEUj3bu +mQg97KtCh4s2xceE/rWxqlOm35GOmdNFiwKBgQDFOJWC8mds1GFSZhG4VyX3cjRxepgkOGY3UTEJ +S4dhP6PvZu0AEaT1IzEjG9MLneZh/fX9HO0ZR1tG08mlQQmZVo8asCeMAQWJQnVVkdso9OCHCeAp +XysuGjsxuD/Qby85RH1TEqTQ9x6K+O1hYGYhaDNrzO8+PSBmhuMUh262gQKBgDCdhnEiEDzEP0Wg +jgudF6llGcUCp7jH7CDc+4A9xJAlBhipswiW/6KCwskTbfr+2VpmO8X8eay1KCIBUibZv+NIq2SB +PGHwi9TRnHHtXRZaFOpKSkUFFcw5gb7q2E8jOMWiM/qiMxYMspFPTCS7siy/z3aEZUPSZuaRnMzE +15r7AoGBAMf45K+exgsuWSi18RwQqk/RO8ZVZXSep3XnRdGIFeh4SzaMnT/sUMGyLfnrSOzwxSui +nIE1a6cgCWBtyYqQ6Lw1Byh9lDs8OTGY/EtY4L/QO8nMmS0NKroYNPUmnKQhg+qOH/AFh/22uDLK +hEardSx8CzhNujiIGwdg+7F2MiwP +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/examples/mp-rest-jwt-jwk/src/test/resources/privateKey004.pem b/examples/mp-rest-jwt-jwk/src/test/resources/privateKey004.pem new file mode 100644 index 00000000000..23451b549fa --- /dev/null +++ b/examples/mp-rest-jwt-jwk/src/test/resources/privateKey004.pem @@ -0,0 +1,24 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCI1qiNxfsBIb7n57Ha7gfvae+K +x+v63J0VUeuShwt0NRr9TLZBe+oH7CnXgLWYl2tacAHaiqVjxG65pyF0WDsWAO2CbVd0G/g5GqcX +qWOuditshwC2KDWKXUr7wlBlLL1Y0y8EX0swaNjdjcbaHDduyK3T6UlBo/ub9mbBLAhzotKk/fAs +HDa7cjkg7TkFNtmy1XdRwNGWWb9ypT/SBkkTLoyw1tCJesdfls3/GzDbnoKvuw+xK5OZJXHkzy05 +zAU4qa+SUNucOqJ0zDu6fgi9wy3zCmKcYiacqLgCKIG0NEEaWCPzv2I3IlrXEpiYc17VaQmGPBBn +9mBtmIIEACCHAgMBAAECggEAbc7MPdDFBvh8iP6N4+Clr4L0PgsGnC3TRFuTzebe0ycWfHPFwbDd +cfQa85uOnl/MPyuo4SXnaLMmI4cxunpfF94wujxiNIOJYtG3iq5clpCvcgy4DnUf2ePZm0QoXbhU +TeZSUZDi9nr8pHX0P+zqstUJYQdQyQL9kv9dH+Dk+11eM679NBJW/T+bwKKnfV1NHYhe2Ld9SyoK +glzLfYy9sF7kagHFtlAfzaGsNvaAXmeZ6YlZsHrBnqOkikwwIJqfcMooL8LK2EWzms7cjFZzonma +yRQ0W1AwsUDLMjXmLVC4FhfP0WRfZKI1OXCk0oTISi6iIErSwuC2eMWoTiyq8QKBgQDEChvi9T6I +bpwO043iz8v5Hcj12XQjcxNUQB/nJMY9wM/wvD+2BtvLKOVKXMW7y+GibA/hWJIOXkcTmRi2wdUA +s+gQbAlofjLVbYkLXM6MENmRTNXOURF0eGGrOOXrzosYZme18GTjfEhy9bAIKG6RhDSxZVF9exoj +AK00NE9X+QKBgQCysRz09AE0lr7h/ZaEWZm7X7mhYep85HW/3rTYvaTFf4edv0wUB+VjD4tsvitE +T7b+hsdzrGfW8+Z/Iked+e9lABP0eM6dT4hpkqS3rcUPn59WpcqrYSJ7PHVKmgwbztYdmHiPzxUn +qkxDvJNhslWGX+9GMjYweLVjgibTkrZcfwKBgF5Z1y4WhrA3PBjOrP06sZsGQNBChmkBW44zBqfC +xT63a90bXTaIeoR+/Ewb9nb6G3CGveXhMPqFWYQPLRvYkmGyNMCinqySAHlELK8xTZ+QBIawCj8w +OUxrG+bCjbY+RCfMMaIZPxVVnbDmmoBypTSYApxWfS/9bYjnLHVxr7ZRAoGBAKrLsULMqw5J+99k +FGcigVdgcry3K3r+nzGqu67i7Ug80jJMM3p95ZoetIRW7GIZ025LAv8kTgheDfV8nXl4+IHQZkJo +6gvghiFqofhSpqV9S751L1dJu7yRGAcbYPF/bJbTMoE6TR0hoE2qRDDAVRDgR4MP4U3JQo7/Sv81 +HwsfAoGAKWK3v80fbklOs0eP0c8h97d8PwjlbK13h4paFK1D29ftYh9I3T/Fbcr0oGRvAORZ210T +pODTW2j7SO2Q2jO2dFGTnabAYUoZrgztU97hWG2QGSVjil1HYmgqoKPijkydmW0i0Bj87/1SpFHQ +G3XrPbgOH3T6Xbezrl9oyJ4qvEQ= +-----END PRIVATE KEY----- \ No newline at end of file From 73f62344b8e5770f4b1033a5b2cd1062e084c4d1 Mon Sep 17 00:00:00 2001 From: cotnic Date: Thu, 3 Jan 2019 22:00:27 +0100 Subject: [PATCH 3/3] TOMEE-2334: improvement of code based on comments from @jeanouii --- examples/mp-rest-jwt-jwk/README.adoc | 7 +++--- examples/mp-rest-jwt-jwk/pom.xml | 22 ------------------- .../org/superbiz/rest/KeyGeneratorUtil.java | 16 ++++++++++++++ .../java/org/superbiz/rest/ProductsTest.java | 16 ++++++++++++++ 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/examples/mp-rest-jwt-jwk/README.adoc b/examples/mp-rest-jwt-jwk/README.adoc index 08e9969b4b4..ff5a97e9116 100644 --- a/examples/mp-rest-jwt-jwk/README.adoc +++ b/examples/mp-rest-jwt-jwk/README.adoc @@ -33,8 +33,9 @@ project: .... . Annotate our `Application.class` with `@LoginConfig(authMethod = "MP-JWT")` -. Provide public and private key for authentication. And specify the location of the public key and the issuer in our -`microprofile-config.properties` file. +. Provide public key for validation of the JWT. And specify the location of the public key and the issuer in our +`microprofile-config.properties` file. The public key is then used for verification of the signature in the +JWT. + [source,properties] ---- @@ -69,7 +70,7 @@ The application enables us to manipulate and view products with specific users. We access endpoints from our test class by creating a `JWT` with the help of our `TokenUtils.generateJWTString(String jsonResource, String keyId)` which signs our user -data in json format with the help of our `src/test/resources/{keyId}` key. +data in json format with the help of our `src/test/resources/{keyId}` private key. We can also generate new `privateKey.pem` and `publicKey.pem` with the `GenerateKeyUtils.generateKeyPair(String keyAlgorithm, int keySize)` method which diff --git a/examples/mp-rest-jwt-jwk/pom.xml b/examples/mp-rest-jwt-jwk/pom.xml index 8a2e02553a5..a488c0ea873 100644 --- a/examples/mp-rest-jwt-jwk/pom.xml +++ b/examples/mp-rest-jwt-jwk/pom.xml @@ -131,28 +131,6 @@ test - - - org.apache.tomee - openejb-cxf-rs - ${tomee.version} - test - - - - org.apache.tomee - openejb-core - ${tomee.version} - test - - - commons-lang - commons-lang - 2.4 - org.jboss.arquillian.junit arquillian-junit-container diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java index e9f9949a228..0ceaf02b592 100644 --- a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/KeyGeneratorUtil.java @@ -1,3 +1,19 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.superbiz.rest; import com.nimbusds.jose.jwk.KeyUse; diff --git a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java index 2eb6dfb8579..9f569a69dfe 100644 --- a/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java +++ b/examples/mp-rest-jwt-jwk/src/test/java/org/superbiz/rest/ProductsTest.java @@ -1,3 +1,19 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.superbiz.rest; import org.eclipse.microprofile.rest.client.inject.RestClient;