diff --git a/pom.xml b/pom.xml index 36326ac..4abc35f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ io.github.isa-group Pricing4Java - 5.5.1 + 5.6.0-SNAPSHOT ${project.groupId}:${project.artifactId} A pricing driven feature toggling library for java @@ -49,13 +49,14 @@ - 2.14.2 - 1.9.7 - 6.1.5 - 3.2.0 17 17 UTF-8 + 0.12.6 + 1.9.7 + 6.1.5 + 3.2.0 + 2.3 @@ -143,42 +144,35 @@ io.jsonwebtoken - jjwt - 0.9.1 - - - org.json - json - 20250107 + jjwt-api + ${jjwt.version} - - org.yaml - snakeyaml - 2.3 + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + test - - jakarta.xml.bind - jakarta.xml.bind-api - 2.3.2 + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + test - + - org.glassfish.jaxb - jaxb-runtime - 2.3.2 + org.yaml + snakeyaml + ${snakeyaml.version} Pricing4Java - - org.apache.maven.plugins maven-gpg-plugin diff --git a/src/main/java/io/github/isagroup/PricingContext.java b/src/main/java/io/github/isagroup/PricingContext.java index bdde2a0..70c9691 100644 --- a/src/main/java/io/github/isagroup/PricingContext.java +++ b/src/main/java/io/github/isagroup/PricingContext.java @@ -29,23 +29,44 @@ public abstract class PricingContext { private static final Logger logger = LoggerFactory.getLogger(PricingContext.class); /** - * Returns path of the pricing configuration YAML file. - * This file should be located in the resources folder, and the path should be - * relative to it. + * Returns the path to the Pricing2Yaml configuration file. The {@link String} + * path given to the implementation of this method should point to a + * Pricing2Yaml file under {@code resources} folder. * - * @return Configuration file path + * @return a path as {@link String} to a Pricing2Yaml configuration file + * relative to the {@code resources} folder */ public abstract String getConfigFilePath(); /** - * Returns the secret used to encode the pricing JWT. - * * @return JWT secret String + * Returns the secret used to sign the pricing JWT. The secret key needs to be + * encoded in {@code base64}. Internally JWT library will choose the best + * algorithm to sign the JWT ({@code HS256}, {@code HS384} or {@code HS512}), if + * the secret key bit length does not conform to the minimun stated by these + * algorithms will throw a {@link io.jsonwebtoken.security.WeakKeyException} + * + * @return a pricing secret encoded in {@code base64} + * @see Signature + * Algorithm Keys + * @see HMAC + * with SHA-2 Functions */ public abstract String getJwtSecret(); /** - * Returns the secret used to encode the authorization JWT. - * * @return JWT secret String + * Returns the secret used to sign the authorization JWT. The secret key needs + * to be encoded in {@code base64}. Internally JWT library will choose the best + * algorithm to sign the JWT ({@code HS256}, {@code HS384} or {@code HS512}), if + * the secret key bit length does not conform to the minimun stated by these + * algorithms will throw a {@link io.jsonwebtoken.security.WeakKeyException} + * + * @return a pricing secret encoded in {@code base64} + * @see Signature + * Algorithm Keys + * @see HMAC + * with SHA-2 Functions */ public String getAuthJwtSecret() { return this.getJwtSecret(); @@ -66,7 +87,8 @@ public int getJwtExpiration() { * for them. * * @return A {@link Boolean} indicating the condition to include, or not, - * the pricing evaluation context in the JWT. + * the pricing evaluation context in the JWT. Set to {@code true} by + * default * * @see PricingEvaluatorUtil#generateUserToken * @@ -77,9 +99,8 @@ public Boolean userAffectedByPricing() { /** * This method should return the user context that will be used to evaluate the - * pricing plan. - * It should be considered which users has accessed the service and what - * information is available. + * pricing plan. It should be considered which users has accessed the service + * and what information is available. * * @return Map with the user context */ @@ -90,18 +111,18 @@ public Boolean userAffectedByPricing() { * With this information, the library will be able to build the {@link Plan} * object of the user from the configuration. * - * @return String with the current user's plan name + * @return a {@link String} with the current user's plan name */ public abstract String getUserPlan(); /** * This method should return a list with the name of the add-ons contracted by - * the current user. If the pricing don't include add-ons, then just return an empty array. - * With this information, the library will be able to build the subscription of - * the user from the configuration. + * the current user. If the pricing does not include add-ons, then just return + * an empty {@link List}. With this information, the library will be able to + * build the subscription of the user from the configuration. * - * @return {@code List} with the current user's contracted add-ons. Add-on names - * should be the same as in the pricing configuration file. + * @return a list with the current user's contracted add-ons. + * Add-on names should be the same as in the pricing configuration file. * */ public abstract List getUserAddOns(); @@ -109,11 +130,16 @@ public Boolean userAffectedByPricing() { /** * Returns a list with the full subscription contracted by the current user * (including plans and add-ons). + *

+ * There are two keys inside this {@link Map}: + *

    + *
  • Key {@code plans} contains the plan name of the user + *
  • Key {@code addOns} contains a list with the add-ons contracted by the + * user + *
* - * Key "plan" contains the plan name of the user. - * Key "addOns" contains a list with the add-ons contracted by the user. - * - * @return {@code Map} with the current user's contracted subscription. + * @return {@code Map} with the current user's contracted + * subscription. */ public final Map getUserSubscription() { Map userSubscription = new HashMap<>(); @@ -164,7 +190,7 @@ public final Map getPlanContext() { * This method returns the {@link PricingManager} object that is being used to * evaluate the pricing plan. * - * @return PricingManager object + * @return {@link PricingManager} object */ public final PricingManager getPricingManager() { try { diff --git a/src/main/java/io/github/isagroup/PricingEvaluatorUtil.java b/src/main/java/io/github/isagroup/PricingEvaluatorUtil.java index 29d9d92..29e1101 100644 --- a/src/main/java/io/github/isagroup/PricingEvaluatorUtil.java +++ b/src/main/java/io/github/isagroup/PricingEvaluatorUtil.java @@ -1,17 +1,20 @@ package io.github.isagroup; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import java.util.logging.Logger; -import io.github.isagroup.models.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.stereotype.Component; import io.github.isagroup.exceptions.PricingPlanEvaluationException; +import io.github.isagroup.models.Feature; +import io.github.isagroup.models.FeatureStatus; +import io.github.isagroup.models.PlanContextManager; +import io.github.isagroup.models.PricingManager; import io.github.isagroup.services.jwt.PricingJwtUtils; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; /** * Utility class that provides methods to generate and manage JWT that contains @@ -58,23 +61,19 @@ public String generateUserToken() { planContextManager.setUserContext(pricingContext.getUserContext()); claims.put("userContext", planContextManager.getUserContext()); } catch (Exception e) { - throw new PricingPlanEvaluationException("Error while retrieving user context! Please check your PricingContext.getUserContext() method"); + throw new PricingPlanEvaluationException( + "Error while retrieving user context! Please check your PricingContext.getUserContext() method"); } if (!pricingContext.userAffectedByPricing()) { - return Jwts.builder() - .setClaims(claims) - .setSubject(subject) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + pricingContext.getJwtExpiration())) - .signWith(SignatureAlgorithm.HS512, pricingContext.getJwtSecret()) - .compact(); + return jwtUtils.createJwtToken(claims, subject); } try { planContextManager.setPlanContext(pricingContext.getPlanContext()); } catch (NullPointerException e) { - throw new PricingPlanEvaluationException("Error while retrieving plan context! Please check your configuration file or add a plan with the given name"); + throw new PricingPlanEvaluationException( + "Error while retrieving plan context! Please check your configuration file or add a plan with the given name"); } PricingManager pricingManager = pricingContext.getPricingManager(); @@ -86,18 +85,11 @@ public String generateUserToken() { claims.put("features", featureStatuses); claims.put("planContext", planContextManager.getPlanContext()); - return Jwts.builder() - .setClaims(claims) - .setSubject(subject) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + pricingContext.getJwtExpiration())) - .signWith(SignatureAlgorithm.HS512, pricingContext.getJwtSecret()) - .compact(); + return jwtUtils.createJwtToken(claims, subject); } - private Map computeFeatureStatuses(PlanContextManager planContextManager, - Map features) { + Map features) { Map featureStatuses = new HashMap<>(); @@ -109,10 +101,11 @@ private Map computeFeatureStatuses(PlanContextManager pla String expression = features.get(featureName).getExpression(); try { Boolean eval = FeatureStatus.computeFeatureEvaluation(expression, planContextManager) - .orElseThrow(() -> new PricingPlanEvaluationException("Evaluation was null")); + .orElseThrow(() -> new PricingPlanEvaluationException("Evaluation was null")); featureStatus.setEval(eval); } catch (SpelEvaluationException e) { - throw new PricingPlanEvaluationException("Error while evaluating the expression of the feature " + featureName + "! Please check the expression"); + throw new PricingPlanEvaluationException("Error while evaluating the expression of the feature " + + featureName + "! Please check the expression"); } Optional userContextKey = FeatureStatus.computeUserContextVariable(expression); @@ -124,9 +117,12 @@ private Map computeFeatureStatuses(PlanContextManager pla featureStatus.setUsed(planContextManager.getUserContext().get(userContextKey.get())); if (feature.getExpression().contains("usageLimits")) { String usageLimitName = feature.getExpression().split("usageLimits")[1].split("[',\"]")[2]; - featureStatus.setLimit(((Map) planContextManager.getPlanContext().get("usageLimits")).get(usageLimitName)); + featureStatus + .setLimit(((Map) planContextManager.getPlanContext().get("usageLimits")) + .get(usageLimitName)); } else { - featureStatus.setLimit(((Map) planContextManager.getPlanContext().get("features")).get(featureName)); + featureStatus.setLimit(((Map) planContextManager.getPlanContext().get("features")) + .get(featureName)); } } @@ -148,7 +144,7 @@ private Map computeFeatureStatuses(PlanContextManager pla * @param expression the expression of the feature that will replace its * evaluation * @return Modified version of the provided JWT that contains the new expression - * in the "eval" attribute of the feature. + * in the "eval" attribute of the feature. */ public String addExpressionToToken(String token, String featureId, String expression) { @@ -173,13 +169,7 @@ private String buildJwtToken(Map> features, String s claims.put("userContext", pricingContext.getUserContext()); claims.put("planContext", pricingContext.getPlanContext()); - return Jwts.builder() - .setClaims(claims) - .setSubject(subject) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + pricingContext.getJwtExpiration())) - .signWith(SignatureAlgorithm.HS512, pricingContext.getJwtSecret()) - .compact(); + return jwtUtils.createJwtToken(claims, subject); } } diff --git a/src/main/java/io/github/isagroup/services/jwt/PricingJwtUtils.java b/src/main/java/io/github/isagroup/services/jwt/PricingJwtUtils.java index ede532f..2e2ddb4 100644 --- a/src/main/java/io/github/isagroup/services/jwt/PricingJwtUtils.java +++ b/src/main/java/io/github/isagroup/services/jwt/PricingJwtUtils.java @@ -1,9 +1,10 @@ package io.github.isagroup.services.jwt; import java.util.Date; -import java.util.HashMap; import java.util.Map; +import javax.crypto.SecretKey; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -11,12 +12,11 @@ import io.github.isagroup.PricingContext; import io.github.isagroup.PricingEvaluatorUtil; -import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.SignatureException; import io.jsonwebtoken.UnsupportedJwtException; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; /** * Utility class that provides methods to generate and manage JWT. @@ -24,117 +24,132 @@ @Component public class PricingJwtUtils { - @Autowired - private PricingContext pricingContext; - - public PricingJwtUtils(PricingContext pricingContext) { - this.pricingContext = pricingContext; - } - - private static final Logger logger = LoggerFactory.getLogger(PricingJwtUtils.class); - - /** - * Extracts the subject from the given JWT. - * - * @param token a JWT that contains a subject - * @return The subject of the JWT - */ - public String getSubjectFromJwtToken(String token) { - return Jwts.parser().setSigningKey(pricingContext.getJwtSecret()).parseClaimsJws(token).getBody().getSubject(); - } - - /** - * Generates a JWT from the given username that does not contains pricing - * evaluation. - * - * @param username The username to be used as the subject of the JWT - * @return The generated JWT - */ - public String generateTokenFromUsername(String username) { - Map claims = new HashMap<>(); - return Jwts.builder().setClaims(claims).setSubject(username).setIssuedAt(new Date()) - .setExpiration(new Date((new Date()).getTime() + pricingContext.getJwtExpiration())) - .signWith(SignatureAlgorithm.HS512, pricingContext.getJwtSecret()).compact(); - } - - /** - * Extracts the features from a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * - * @param token a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * @return A Map that contains the evaluation of all the features for the - * current user located in the JWT body - */ - public Map> getFeaturesFromJwtToken(String token) { - return (Map>) Jwts.parser().setSigningKey(pricingContext.getJwtSecret()) - .parseClaimsJws(token).getBody().get("features"); - } - - /** - * Extracts the plan context from a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * - * @param token a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * @return A Map that contains the plan context used in the evaluation of - * features located in the JWT body - */ - public Map getPlanContextFromJwtToken(String token) { - return (Map) Jwts.parser().setSigningKey(pricingContext.getJwtSecret()).parseClaimsJws(token) - .getBody().get("planContext"); - } - - /** - * Extracts the user context from a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * - * @param token a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * @return A Map that contains the user context used in the evaluation of - * features located in the JWT body - */ - public Map getUserContextFromJwtToken(String token) { - return (Map) Jwts.parser().setSigningKey(pricingContext.getJwtSecret()).parseClaimsJws(token) - .getBody().get("userContext"); - } - - /** - * Extracts the username from a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method. - * It is the equivalent of getting the token's subject - * - * @param token a JWT generated by - * {@link PricingEvaluatorUtil#generateUserToken()} method - * @return The username of the user located in the JWT body - */ - public String getUserNameFromJwtToken(String token) { - return Jwts.parser().setSigningKey(pricingContext.getJwtSecret()).parseClaimsJws(token).getBody().getSubject(); - } - - /** - * Validates a JWT - * It is the equivalent of getting the token's subject - * - * @param authToken a JWT String - * @return true if the token is correct, false otherwise - */ - public boolean validateJwtToken(String authToken) { - try { - Jwts.parser().setSigningKey(pricingContext.getAuthJwtSecret()).parseClaimsJws(authToken); - return true; - } catch (SignatureException e) { - logger.error("Invalid JWT signature: {}", e.getMessage()); - } catch (MalformedJwtException e) { - logger.error("Invalid JWT: {}", e.getMessage()); - } catch (ExpiredJwtException e) { - logger.error("JWT is expired: {}", e.getMessage()); - } catch (UnsupportedJwtException e) { - logger.error("JWT is unsupported: {}", e.getMessage()); - } catch (IllegalArgumentException e) { - logger.error("JWT claims string is empty: {}", e.getMessage()); - } - - return false; - } + @Autowired + private PricingContext pricingContext; + + private final SecretKey pricingSecretKey; + + public PricingJwtUtils(PricingContext pricingContext) { + this.pricingContext = pricingContext; + this.pricingSecretKey = createKeyForBase64String(pricingContext.getJwtSecret()); + } + + /** + * Given a base64 encoded {@link String} creates a {@link SecretKey} to be used + * when signing a JWT token. Given string must meet HMAC-SHA bit length + * requirements + * + * @param base64String + * @return {@link javax.crypto.SecretKey} + * @throws {@link io.jsonwebtoken.security.WeakKeyException} if the string is + * not strong enough to be used with HMAC-SHA algorithms + */ + private static SecretKey createKeyForBase64String(String base64String) { + return Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64String)); + } + + private static final Logger LOGGER = LoggerFactory.getLogger(PricingJwtUtils.class); + + /** + * Given a map claims and subject creates a JWT token given + * {@link PricingContext} configuation + * + * @param claims a {@link Map} of claims + * @param subject a target of the token + * @return The subject of the JWT + */ + public String createJwtToken(Map claims, String subject) { + + return Jwts.builder() + .claims(claims) + .subject(subject) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + pricingContext.getJwtExpiration())) + .signWith(pricingSecretKey) + .compact(); + } + + /** + * Extracts the subject from the given JWT. + * + * @param token a JWT that contains a subject + * @return The subject of the JWT + */ + public String getSubjectFromJwtToken(String token) { + return Jwts.parser().verifyWith(pricingSecretKey) + .build() + .parseSignedClaims(token).getPayload().getSubject(); + } + + /** + * Extracts the features from a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * + * @param token a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * @return A Map that contains the evaluation of all the features for the + * current user located in the JWT body + */ + public Map> getFeaturesFromJwtToken(String token) { + return (Map>) Jwts.parser() + .verifyWith(pricingSecretKey).build() + .parseSignedClaims(token) + .getPayload().get("features"); + } + + /** + * Extracts the plan context from a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * + * @param token a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * @return A Map that contains the plan context used in the evaluation of + * features located in the JWT body + */ + public Map getPlanContextFromJwtToken(String token) { + return (Map) Jwts.parser() + .verifyWith(pricingSecretKey).build() + .parseSignedClaims(token) + .getPayload().get("planContext"); + } + + /** + * Extracts the user context from a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * + * @param token a JWT generated by + * {@link PricingEvaluatorUtil#generateUserToken()} method + * @return A Map that contains the user context used in the evaluation of + * features located in the JWT body + */ + public Map getUserContextFromJwtToken(String token) { + return (Map) Jwts.parser() + .verifyWith(pricingSecretKey).build() + .parseSignedClaims(token) + .getPayload().get("userContext"); + } + + /** + * Validates a JWT + * It is the equivalent of getting the token's subject + * + * @param authToken a JWT String + * @return true if the token is correct, false otherwise + */ + public boolean validateJwtToken(String authToken) { + try { + Jwts.parser().verifyWith(createKeyForBase64String(pricingContext.getAuthJwtSecret())) + .build() + .parseSignedClaims(authToken); + return true; + } catch (UnsupportedJwtException e) { + LOGGER.error("jwt {} argument does not represent a signed Claims JWT: ", authToken, e); + } catch (JwtException e) { + LOGGER.error("jwt {} cannot be parsed or validated as required: ", authToken, e); + } catch (IllegalArgumentException e) { + LOGGER.error("Illegal argument for token", e); + } + + return false; + } } diff --git a/src/test/java/io/github/isagroup/PricingContextTestImpl.java b/src/test/java/io/github/isagroup/PricingContextTestImpl.java index ac9e91f..8b5fa18 100644 --- a/src/test/java/io/github/isagroup/PricingContextTestImpl.java +++ b/src/test/java/io/github/isagroup/PricingContextTestImpl.java @@ -4,8 +4,13 @@ import java.util.List; import java.util.Map; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Encoders; + public class PricingContextTestImpl extends PricingContext { + static final String JWT_SUBJECT_TEST = "admin1"; + private String path; private String secret; private Integer jwtExpiration; @@ -14,12 +19,12 @@ public class PricingContextTestImpl extends PricingContext { private Map userContext; public PricingContextTestImpl() { - this.path = null; - this.secret = "defualtSecret"; + this.path = "pricing/petclinic.yml"; + this.secret = Encoders.BASE64.encode(Jwts.SIG.HS256.key().build().getEncoded()); this.jwtExpiration = 86400; - this.userPlan = null; + this.userPlan = "ADVANCED"; this.userAddOns = new ArrayList<>(); - this.userContext = null; + this.userContext = Map.of("username", JWT_SUBJECT_TEST, "pets", 2); } @Override diff --git a/src/test/java/io/github/isagroup/PricingEvaluatorUtilTests.java b/src/test/java/io/github/isagroup/PricingEvaluatorUtilTests.java index c66427c..016440d 100644 --- a/src/test/java/io/github/isagroup/PricingEvaluatorUtilTests.java +++ b/src/test/java/io/github/isagroup/PricingEvaluatorUtilTests.java @@ -1,9 +1,7 @@ package io.github.isagroup; -import java.util.HashMap; import java.util.Map; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.github.isagroup.services.jwt.PricingJwtUtils; @@ -12,39 +10,11 @@ public class PricingEvaluatorUtilTests { - private static final String JWT_SECRET_TEST = "secret"; - private static final Integer JWT_EXPIRATION_TEST = 86400; - private static final String JWT_SUBJECT_TEST = "admin1"; - private static final String JWT_EXPRESSION_TEST = "userContext['pets']*4 < planContext['usageLimits']['pets']"; + private PricingContext pricingContext = new PricingContextTestImpl(); - private static final String USER_PLAN = "ADVANCED"; - private static final String YAML_CONFIG_PATH = "pricing/petclinic.yml"; + private PricingEvaluatorUtil pricingEvaluatorUtil = new PricingEvaluatorUtil(pricingContext); - private PricingContext pricingContext; - - private PricingEvaluatorUtil pricingEvaluatorUtil; - - private PricingJwtUtils jwtUtils; - - @BeforeEach - public void setUp() { - - Map userContext = new HashMap<>(); - userContext.put("username", JWT_SUBJECT_TEST); - userContext.put("pets", 2); - - PricingContextTestImpl pricingContext = new PricingContextTestImpl(); - - pricingContext.setJwtExpiration(JWT_EXPIRATION_TEST); - pricingContext.setJwtSecret(JWT_SECRET_TEST); - pricingContext.setUserContext(userContext); - pricingContext.setUserPlan(USER_PLAN); - pricingContext.setConfigFilePath(YAML_CONFIG_PATH); - - this.pricingContext = pricingContext; - this.pricingEvaluatorUtil = new PricingEvaluatorUtil(pricingContext); - this.jwtUtils = new PricingJwtUtils(pricingContext); - } + private PricingJwtUtils jwtUtils = new PricingJwtUtils(pricingContext); @Test void simpleTokenGenerationTest() { @@ -71,7 +41,7 @@ void checkTokenSubjectTest() { String jwtSubject = jwtUtils.getSubjectFromJwtToken(token); assertTrue(jwtUtils.validateJwtToken(token), "Token is not valid"); - assertEquals(JWT_SUBJECT_TEST, jwtSubject, "The subject has not being correctly set"); + assertEquals(PricingContextTestImpl.JWT_SUBJECT_TEST, jwtSubject, "The subject has not being correctly set"); } @@ -79,14 +49,15 @@ void checkTokenSubjectTest() { void tokenExpressionsTest() { String firstToken = pricingEvaluatorUtil.generateUserToken(); + String jwtExpressionTest = "userContext['pets']*4 < planContext['usageLimits']['pets']"; String newToken = pricingEvaluatorUtil.addExpressionToToken(firstToken, "visits", - JWT_EXPRESSION_TEST); + jwtExpressionTest); Map> features = jwtUtils.getFeaturesFromJwtToken(newToken); assertTrue(jwtUtils.validateJwtToken(newToken), "Token is not valid"); - assertEquals(JWT_EXPRESSION_TEST, (String) features.get("visits").get("eval"), + assertEquals(jwtExpressionTest, (String) features.get("visits").get("eval"), "The expression for the feature visits has not being correctly set"); } diff --git a/src/test/java/io/github/isagroup/PricingPlanAwareTests.java b/src/test/java/io/github/isagroup/PricingPlanAwareTests.java index ae561af..d8256c8 100644 --- a/src/test/java/io/github/isagroup/PricingPlanAwareTests.java +++ b/src/test/java/io/github/isagroup/PricingPlanAwareTests.java @@ -34,7 +34,7 @@ io.github.isagroup.services.jwt.PricingJwtUtils.class }) public class PricingPlanAwareTests { - private static final String JWT_SECRET_TEST = "secret"; + private static final String JWT_SECRET_TEST = "qfqj73ZGIN1XxPvI5mG6dVaXqpY4XVeOOBjp4zf0yNE="; private static final Integer JWT_EXPIRATION_TEST = 86400; private static final String JWT_SUBJECT_TEST = "admin1"; private static final String CONFIG_FILE_PATH_TEST = "pricing/petclinic.yml"; diff --git a/src/test/java/io/github/isagroup/pricingcontext/PricingConfigExpirationTest.java b/src/test/java/io/github/isagroup/pricingcontext/PricingConfigExpirationTest.java index 1a5c60d..043384a 100644 --- a/src/test/java/io/github/isagroup/pricingcontext/PricingConfigExpirationTest.java +++ b/src/test/java/io/github/isagroup/pricingcontext/PricingConfigExpirationTest.java @@ -13,6 +13,8 @@ import io.github.isagroup.PricingContext; import io.github.isagroup.PricingEvaluatorUtil; import io.github.isagroup.services.jwt.PricingJwtUtils; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Encoders; public class PricingConfigExpirationTest { @@ -38,7 +40,7 @@ public String getConfigFilePath() { @Override public String getJwtSecret() { - return "p3tclinic"; + return Encoders.BASE64.encode(Jwts.SIG.HS256.key().build().getEncoded()); } @Override