From db366b5342056df8f2e349fcd5453f82b170337c Mon Sep 17 00:00:00 2001 From: Mike Andrasak Date: Fri, 13 Sep 2019 15:42:25 -0400 Subject: [PATCH] Issue 335 support mpjwt using system properties --- .../common/boosters/MPJWTBoosterConfig.java | 11 + .../boost/common/config/BoostProperties.java | 14 +- .../src/it/test-mp-jwt-1.1-sysprop/pom.xml | 278 ++++++++++++++++++ .../guides/inventory/JwtResource.java | 73 +++++ .../inventory/JwtResourceApplication.java | 22 ++ .../src/main/webapp/WEB-INF/web.xml | 10 + .../src/main/webapp/index.html | 78 +++++ .../src/test/java/it/jwt/JwtIT.java | 122 ++++++++ .../src/test/java/it/jwt/util/JwtBuilder.java | 140 +++++++++ .../test/java/it/jwt/util/JwtVerifier.java | 131 +++++++++ .../src/test/java/it/jwt/util/TestUtils.java | 47 +++ .../boosters/LibertyMPJWTBoosterConfig.java | 8 +- 12 files changed, 931 insertions(+), 3 deletions(-) create mode 100755 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/pom.xml create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResource.java create mode 100755 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResourceApplication.java create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/WEB-INF/web.xml create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/index.html create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/JwtIT.java create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtBuilder.java create mode 100755 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtVerifier.java create mode 100644 boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/TestUtils.java diff --git a/boost-common/src/main/java/boost/common/boosters/MPJWTBoosterConfig.java b/boost-common/src/main/java/boost/common/boosters/MPJWTBoosterConfig.java index 4151d52f..9ee5b545 100644 --- a/boost-common/src/main/java/boost/common/boosters/MPJWTBoosterConfig.java +++ b/boost-common/src/main/java/boost/common/boosters/MPJWTBoosterConfig.java @@ -10,23 +10,34 @@ *******************************************************************************/ package boost.common.boosters; +import static boost.common.config.ConfigConstants.DB2_DEFAULT_PORT_NUMBER; +import static boost.common.config.ConfigConstants.DERBY_DB; +import static boost.common.config.ConfigConstants.MYSQL_DEFAULT_PORT_NUMBER; + import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Properties; import boost.common.BoostException; import boost.common.BoostLoggerI; import boost.common.boosters.AbstractBoosterConfig.BoosterCoordinates; +import boost.common.config.BoostProperties; @BoosterCoordinates(AbstractBoosterConfig.BOOSTERS_GROUP_ID + ":mp-jwt") public class MPJWTBoosterConfig extends AbstractBoosterConfig { + protected Properties boostMPProperties; + public MPJWTBoosterConfig(Map dependencies, BoostLoggerI logger) throws BoostException { super(dependencies.get(getCoordinates(MPJWTBoosterConfig.class))); + + boostMPProperties = BoostProperties.getConfiguredMPProperties(logger); } @Override public List getDependencies() { return new ArrayList(); } + } diff --git a/boost-common/src/main/java/boost/common/config/BoostProperties.java b/boost-common/src/main/java/boost/common/config/BoostProperties.java index 7d05b95a..31f06c17 100644 --- a/boost-common/src/main/java/boost/common/config/BoostProperties.java +++ b/boost-common/src/main/java/boost/common/config/BoostProperties.java @@ -53,13 +53,25 @@ public static Map getPropertiesToEncrypt() { } public static Properties getConfiguredBoostProperties(BoostLoggerI logger) { + + return getConfiguredBoostPropertiesFiltered(logger, "boost."); + + } + + public static Properties getConfiguredMPProperties(BoostLoggerI logger) { + + return getConfiguredBoostPropertiesFiltered(logger, "mp.jwt."); + + } + + public static Properties getConfiguredBoostPropertiesFiltered(BoostLoggerI logger, String filterString) { Properties systemProperties = System.getProperties(); Properties boostProperties = new Properties(); for (Map.Entry entry : systemProperties.entrySet()) { - if (entry.getKey().toString().startsWith("boost.")) { + if (entry.getKey().toString().startsWith(filterString)) { // logger.debug("Found boost property: " + // entry.getKey() + ":" + entry.getValue()); diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/pom.xml b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/pom.xml new file mode 100755 index 00000000..1b45e844 --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/pom.xml @@ -0,0 +1,278 @@ + + 4.0.0 + boost + test-mpJwt-1.1 + 1.0-SNAPSHOT + war + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + true + + + false + + + + + + + jitpack.io + https://jitpack.io + + + mavenCentral + https://repo.maven.apache.org/maven2 + + + + + UTF-8 + UTF-8 + 1.8 + 1.8 + ${project.build.testOutputDirectory}/truststore/public.key + http://openliberty.io + + + + + + + boost.boosters + mp20-bom + @pom.version@ + pom + import + + + + + + + + + + boost.boosters + jaxrs + + + boost.boosters + jsonp + + + boost.boosters + cdi + + + boost.boosters + mpConfig + + + boost.boosters + mp-jwt + + + + org.glassfish + javax.json + 1.0.4 + test + + + org.apache.cxf + cxf-rt-rs-client + 3.2.6 + test + + + junit + junit + 4.12 + test + + + + org.springframework + spring-context + 4.3.9.RELEASE + test + + + com.github.dev-tools-for-enterprise-java + system-test + v0.1-alpha + test + + + + org.bitbucket.b_c + jose4j + 0.6.5 + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + generate-resources + generate-resources + + + + + + + + + run + + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.0.0 + + + generate-resources + + write-project-properties + + + + + ${project.basedir}/target/liberty/wlp/etc/server.env + + + + + + + + boost + boost-maven-plugin + @pom.version@ + + + + package + + + + test-start-server + pre-integration-test + + start + + + + test-stop-server + post-integration-test + + stop + + + + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M1 + + + integration-test + integration-test + + integration-test + + + + + ${project.build.testOutputDirectory}/truststore/public.key + http://openliberty.io + + + + + verify-results + + verify + + + + + ${project.build.directory}/test-reports/microprofile-jwt/failsafe-summary.xml + ${project.build.directory}/test-reports/microprofile-jwt + + + + + + + ol + + + boostRuntime + ol + + + + + boost.runtimes + openliberty + + + + + wlp + + + boostRuntime + wlp + + + + + boost.runtimes + wlp + + + + + tomee + + + boostRuntime + tomee + + + + + boost.runtimes + tomee + + + + + diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResource.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResource.java new file mode 100644 index 00000000..526fe34c --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResource.java @@ -0,0 +1,73 @@ +// tag::copyright[] +/******************************************************************************* + * Copyright (c) 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - Initial implementation + *******************************************************************************/ +// end::copyright[] +// tag::jwt[] +package io.openliberty.guides.inventory; + +import java.util.Set; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Context; +import org.eclipse.microprofile.jwt.JsonWebToken; +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.core.SecurityContext; +import java.security.Principal; + +@RequestScoped +@Path("jwt") +public class JwtResource { + // The JWT of the current caller. Since this is a request scoped resource, the + // JWT will be injected for each JAX-RS request. The injection is performed by + // the mpJwt-1.1 feature. + @Inject + private JsonWebToken jwtPrincipal; + + @GET + @RolesAllowed({ "admin", "user" }) + @Path("/username") + public Response getJwtUsername() { + System.out.println("Returning JWT User Name"); + return Response.ok(this.jwtPrincipal.getName()).build(); + } + + @GET + @RolesAllowed({ "admin", "user" }) + @Path("/groups") + public Response getJwtGroups(@Context SecurityContext securityContext) { + Set groups = null; + Principal user = securityContext.getUserPrincipal(); + if (user instanceof JsonWebToken) { + JsonWebToken jwt = (JsonWebToken) user; + groups = jwt.getGroups(); + } + return Response.ok(groups.toString()).build(); + } + + @GET + @RolesAllowed({ "admin" }) + @Path("/customClaim") + public Response getCustomClaim(@Context SecurityContext securityContext) { + if (securityContext.isUserInRole("admin")) { + String customClaim = jwtPrincipal.getClaim("customClaim"); + return Response.ok(customClaim).build(); + } else { + System.out.println("Error user is not in role admin"); + return Response.status(Response.Status.FORBIDDEN).build(); + } + + } + +} +// end::jwt[] diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResourceApplication.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResourceApplication.java new file mode 100755 index 00000000..2ea6d71a --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/java/io/openliberty/guides/inventory/JwtResourceApplication.java @@ -0,0 +1,22 @@ +// tag::copyright[] +/** + * ***************************************************************************** + * Copyright (c) 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which accompanies this + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html + * + *

Contributors: IBM Corporation - Initial implementation + * ***************************************************************************** + */ +// end::copyright[] +package io.openliberty.guides.inventory; + +// JAX-RS + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("inventory") +public class JwtResourceApplication extends Application { +} diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/WEB-INF/web.xml b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..a3823f10 --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + Liberty Project + + + index.html + + \ No newline at end of file diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/index.html b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/index.html new file mode 100644 index 00000000..74ec6c74 --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/main/webapp/index.html @@ -0,0 +1,78 @@ + + + +

Welcome to your Liberty Application

+

Thanks for generating this project using the app accelerator. Please see below for some extra information on each of the technologies you chose

+ +
+

REST

+

+ For the complete feature documentation, see the jaxrs-2.0 + feature description in IBM Knowledge Center. +

+
+ +
+

MicroProfile

+

+ The MicroProfile project is an open + community with the aim of optimizing Enterprise Java for a microservices + architecture. MicroProfile will be evolving with guidance from the community. +

+

+ For the complete feature documentation, see the + microProfile-1.0 + feature description in IBM Knowledge Center. +

+

+ If you want to share your thoughts you can post straight to the + MicroProfile Google group. +

+
+
+
+ + diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/JwtIT.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/JwtIT.java new file mode 100644 index 00000000..045b9c85 --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/JwtIT.java @@ -0,0 +1,122 @@ +// tag::copyright[] +/******************************************************************************* + * Copyright (c) 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - Initial implementation + *******************************************************************************/ +// end::copyright[] +// tag::test[] +package it; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.junit.Test; +import org.junit.Before; +import jwt.util.TestUtils; +import jwt.util.JwtVerifier; +import jwt.util.JwtBuilder; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +public class JwtIT { + + private final String TESTNAME = "TESTUSER"; + private final String INV_JWT = "/inventory/jwt"; + + String baseUrl; + + String authHeader; + + String unauthHeader; + + @Before + public void setup() throws Exception { + // These tests is being temporarily skipped when running on TomEE + // until the failures are addressed. + String runtime = System.getProperty("boostRuntime"); + org.junit.Assume.assumeTrue("ol".equals(runtime) || "wlp".equals(runtime)); + String port = System.getProperty("boost.http.port"); + baseUrl = "http://localhost:" + port; + + JwtVerifier jwtvf = new JwtVerifier(); + // create header that should be authorized + authHeader = "Bearer " + jwtvf.createJwt(TESTNAME, "groups=admin"); + // create header that should NOT be authorized + unauthHeader = "Bearer " + jwtvf.createJwt(TESTNAME, "groups=user"); + + String mpPublicKeyLocation = System.getProperty("mp.jwt.verify.publickey.location"); + String mpIssuer = System.getProperty("mp.jwt.verify.issuer"); + + System.out.println("mp PublicKey location = " + mpPublicKeyLocation); + System.out.println("MPISSUER =" + mpIssuer); + // String publicKeyLocation = System.getProperty("boost.public.key"); + /* + * File publicKeyPath = null; String publicKeyAbsolutePath = null; try { + * publicKeyPath = new File(publicKeyLocation); publicKeyAbsolutePath = + * publicKeyPath.getAbsolutePath(); + * System.out.print("Absolute path to public key is " + publicKeyAbsolutePath + + * " \n"); } catch (Exception e) { System.out.println("Error getting path " + + * e.toString()); } + */ + + if (mpPublicKeyLocation != null) + JwtBuilder.storePublicKey(mpPublicKeyLocation); + else + throw new Exception("public key location is null"); + } + + @Test + public void testSuiteGetName() { + this.testJwtGetName(true); + } + + @Test + public void testSuiteGetCustomClaim() { + this.testJwtGetCustomClaim(true); + } + + @Test + public void testSuiteGetCustomClaimUnauthorized() { + this.testJwtGetCustomClaim(false); + } + + public void testJwtGetName(boolean userAuthorized) { + String jwtUrl = baseUrl + INV_JWT + "/username"; + Response jwtResponse = TestUtils.processRequest(jwtUrl, "GET", null, authHeader); + + assertEquals("HTTP response code should have been " + Status.OK.getStatusCode() + ".", + Status.OK.getStatusCode(), jwtResponse.getStatus()); + + String responseName = jwtResponse.readEntity(String.class); + + assertEquals("The test name and jwt token name should match", TESTNAME, responseName); + + } + + public void testJwtGetCustomClaim(boolean userAuthorized) { + String jwtUrl = baseUrl + INV_JWT + "/customClaim"; + if (userAuthorized) { + Response jwtResponse = TestUtils.processRequest(jwtUrl, "GET", null, authHeader); + assertEquals("HTTP response code should have been " + Status.OK.getStatusCode() + ".", + Status.OK.getStatusCode(), jwtResponse.getStatus()); + } else { + Response jwtResponse = TestUtils.processRequest(jwtUrl, "GET", null, unauthHeader); + assertEquals("HTTP response code should have been " + Status.FORBIDDEN.getStatusCode() + ".", + Status.FORBIDDEN.getStatusCode(), jwtResponse.getStatus()); + } + + } + +} +// end::test[] diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtBuilder.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtBuilder.java new file mode 100644 index 00000000..a2b94f4f --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtBuilder.java @@ -0,0 +1,140 @@ +/* +* Copyright (c) 2019 IBM Corporation and others +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* Licensed 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 jwt.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.security.Key; + +import org.jose4j.base64url.SimplePEMEncoder; +import org.jose4j.jwk.RsaJsonWebKey; +import org.jose4j.jwk.RsaJwkGenerator; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.jws.JsonWebSignature; +import org.jose4j.jwt.JwtClaims; +import org.jose4j.jwt.MalformedClaimException; +import org.jose4j.lang.JoseException; + +/** + * Build JWT's for use with Rest clients. The public and private keys will be + * statically initialized and reused until this class goes away. + * + * @author brutif + */ +public class JwtBuilder { + + public static final String MP_JWT_PUBLIC_KEY = "mp_jwt_verify_publickey"; + public static final String MP_JWT_ISSUER = "mp_jwt_verify_issuer"; + + private static final String BEGIN_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----"; + private static final String END_PUBLIC_KEY = "-----END PUBLIC KEY-----"; + + private JwtClaims claims = null; + private JsonWebSignature jws = null; + static RsaJsonWebKey rsajwk = null; + static JwtBuilder me = null; + + // init the single public:private key pair that we will re-use. + private static void init() { + if (rsajwk != null) { + return; + } + try { + rsajwk = RsaJwkGenerator.generateJwk(2048); + rsajwk.setKeyId("keyid"); + } catch (Exception e) { + e.printStackTrace(System.out); + } + } + + public static String getPublicKey() { + init(); + return pemEncode(rsajwk.getPublicKey()); + } + + private static String pemEncode(Key publicKey) { + byte[] encoded = publicKey.getEncoded(); // X509 SPKI + return BEGIN_PUBLIC_KEY + "\r\n" + SimplePEMEncoder.encode(encoded) + END_PUBLIC_KEY; + } + + public static void storePublicKey(String location) throws IOException, Exception { + init(); + if (location != null) { + System.out.println("storePublicKey entry: location=" + location); + BufferedWriter pubKeyWriter = new BufferedWriter(new FileWriter(location)); + pubKeyWriter.write(pemEncode(rsajwk.getPublicKey())); + pubKeyWriter.flush(); + pubKeyWriter.close(); + } else { + throw new Exception("public key location is null"); + } + } + + public static String buildJwt(String subject, String issuer, String[] claims) + throws JoseException, MalformedClaimException { + me = new JwtBuilder(); + init(); + me.claims = new JwtClaims(); + me.jws = new JsonWebSignature(); + + me.jws.setKeyIdHeaderValue(rsajwk.getKeyId()); + me.jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); + // The JWT is signed using the private key, get the key we'll use every time. + me.jws.setKey(rsajwk.getPrivateKey()); + if (subject != null) { + me.claims.setClaim("sub", subject); + me.claims.setClaim("upn", subject); + } + me.claims.setIssuer(issuer); + me.claims.setExpirationTimeMinutesInTheFuture(60); + setClaims(claims); + if (me.claims.getIssuedAt() == null) { + me.claims.setIssuedAtToNow(); + } + me.jws.setPayload(me.claims.toJson()); + return me.jws.getCompactSerialization(); + } + + private static void setClaims(String[] claims) throws MalformedClaimException { + for (String claim : claims) { + if (!claim.contains("=")) + throw new MalformedClaimException( + "Claim did not contain an equals sign (=). Each claim must be of the form 'key=value'"); + int loc = claim.indexOf('='); + String claimName = claim.substring(0, loc); + Object claimValue = claim.substring(loc + 1); + claimValue = handleArrays((String) claimValue); + setClaim(claimName, claimValue); + } + } + + private static Object handleArrays(String claimValue) { + if (!claimValue.contains(",")) { + return claimValue; + } + String[] elements = claimValue.split(","); + return elements; + } + + private static void setClaim(String name, Object value) { + me.claims.setClaim(name, value); + } +} diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtVerifier.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtVerifier.java new file mode 100755 index 00000000..4b0d9d0f --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/JwtVerifier.java @@ -0,0 +1,131 @@ +// ****************************************************************************** +// Copyright (c) 2017 IBM Corporation and others. +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// Contributors: +// IBM Corporation - initial API and implementation +// ****************************************************************************** +package jwt.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.FileInputStream; +import java.io.StringReader; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.StringTokenizer; +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObject; +import javax.json.JsonReader; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.apache.cxf.common.util.Base64Exception; +import org.apache.cxf.common.util.Base64Utility; +import org.junit.Assert; + +import java.security.Key; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.jose4j.base64url.SimplePEMEncoder; +import org.jose4j.jwk.RsaJsonWebKey; +import org.jose4j.jwk.RsaJwkGenerator; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.jws.JsonWebSignature; +import org.jose4j.jwt.JwtClaims; +import org.jose4j.jwt.MalformedClaimException; +import org.jose4j.lang.JoseException; + +public class JwtVerifier { + + // The algorithm used to sign the JWT. + private static final String JWT_ALGORITHM = "SHA256withRSA"; + + private static final String JWT_ISSUER = System.getProperty("jwt.issuer", "http://openliberty.io"); + + // The hostname we'll use in our tests. The hostname of the backend service. + private static final String libertyHostname = "localhost"; + + // The SSL port we'll use in our tests. The ssl port of the backend service. + private static final String libertySslPort = "5050"; + + private static String keystorePath; + + private static final String secret = "secret"; + + /** + * Make a microprofile-compliant JWT with the correct secret key. + * + * @return A base 64 encoded JWT. + */ + public String createJwt(String username, String groups) throws GeneralSecurityException, IOException, Exception { + if (username != null && groups != null) { + String[] claims = new String[2]; + claims[0] = groups; + claims[1] = "customClaim=Custom"; + return JwtBuilder.buildJwt(username, "http://openliberty.io", claims); + } else { + throw new Exception("group or user name is null"); + } + + } + + /** Create a groups array to put in the JWT. */ + private static JsonArray getGroupArray(Set groups) { + JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + + if (groups != null) { + for (String group : groups) { + arrayBuilder.add(group); + } + } + + return arrayBuilder.build(); + } + + public static JsonObject toJsonObj(String json) { + JsonReader jReader = Json.createReader(new StringReader(json)); + return jReader.readObject(); + } + + private Response processRequest(String url, String method, String payload, String authHeader) { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(url); + Builder builder = target.request(); + builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + if (authHeader != null) { + builder.header(HttpHeaders.AUTHORIZATION, authHeader); + } + return (payload != null) ? builder.build(method, Entity.json(payload)).invoke() + : builder.build(method).invoke(); + } +} diff --git a/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/TestUtils.java b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/TestUtils.java new file mode 100644 index 00000000..345d2f87 --- /dev/null +++ b/boost-maven/boost-maven-plugin/src/it/test-mp-jwt-1.1-sysprop/src/test/java/it/jwt/util/TestUtils.java @@ -0,0 +1,47 @@ +// tag::copyright[] +/** + * ***************************************************************************** + * Copyright (c) 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which accompanies this + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html + * + *

Contributors: IBM Corporation - Initial implementation + * ***************************************************************************** + */ +// end::copyright[] +package jwt.util; + +import java.io.StringReader; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonReader; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation.Builder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +public class TestUtils { + + public static Response processRequest(String url, String method, String payload, String authHeader) { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(url); + Builder builder = target.request(); + builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + if (authHeader != null) { + builder.header(HttpHeaders.AUTHORIZATION, authHeader); + } + return (payload != null) ? builder.build(method, Entity.json(payload)).invoke() + : builder.build(method).invoke(); + } + + public static JsonObject toJsonObj(String json) { + JsonReader jReader = Json.createReader(new StringReader(json)); + return jReader.readObject(); + } + +} diff --git a/boost-maven/boost-runtimes/runtime-openliberty/src/main/java/boost/runtimes/openliberty/boosters/LibertyMPJWTBoosterConfig.java b/boost-maven/boost-runtimes/runtime-openliberty/src/main/java/boost/runtimes/openliberty/boosters/LibertyMPJWTBoosterConfig.java index c316cbe4..6526188a 100644 --- a/boost-maven/boost-runtimes/runtime-openliberty/src/main/java/boost/runtimes/openliberty/boosters/LibertyMPJWTBoosterConfig.java +++ b/boost-maven/boost-runtimes/runtime-openliberty/src/main/java/boost/runtimes/openliberty/boosters/LibertyMPJWTBoosterConfig.java @@ -35,8 +35,12 @@ public String getFeature() { } @Override - public void addServerConfig(LibertyServerConfigGenerator libertyServerConfigGenerator) { - + public void addServerConfig(LibertyServerConfigGenerator libertyServerConfigGenerator) throws BoostException { + try { + libertyServerConfigGenerator.addBootstrapProperties(boostMPProperties); + } catch (Exception e) { + throw new BoostException("Error when configuring mp-jwt " + e.toString()); + } } }