diff --git a/CHANGELOG.md b/CHANGELOG.md index 621f4cd37..679fe9cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ available immediately. For example: ```java AeadAlgorithm enc = Jwts.ENC.A256GCM; -SecretKey key = enc.keyBuilder().build(); +SecretKey key = enc.key().build(); String compact = Jwts.builder().setSubject("Joe").encryptWith(key, enc).compact(); Jwe jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact); @@ -56,7 +56,7 @@ Private keys - as fully encoded JSON objects according to the JWK specification supported. The new `Jwks` utility class exists to create JWK builders and parsers as desired. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); SecretJwk jwk = Jwks.builder().forKey(key).build(); assert key.equals(jwk.toKey()); @@ -92,12 +92,12 @@ interfaces now allow anyone to plug in and support custom algorithms with JJWT a Because the `io.jsonwebtoken.security.Keys#secretKeyFor` and `io.jsonwebtoken.security.Keys#keyPairFor` methods accepted the now-deprecated `io.jsonwebtoken.SignatureAlgorithm` enum, they have also been deprecated in favor of -calling new `keyBuilder()` or `keyPairBuilder()` methods on `MacAlgorithm` and `SignatureAlgorithm` instances directly. +calling new `key()` or `keyPair()` builder methods on `MacAlgorithm` and `SignatureAlgorithm` instances directly. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); -KeyPair pair = Jwts.SIG.RS256.keyPairBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); +KeyPair pair = Jwts.SIG.RS256.keyPair().build(); ``` The builders allow for customization of the JCA `Provider` and `SecureRandom` during Key or KeyPair generation if desired, whereas @@ -121,15 +121,34 @@ deprecate some concepts, or in some cases, completely break backwards compatibil support expected congruent behavior with `Jwe` instances (both have digests). -* `io.jsonwebtoken.CompressionCodec` now inherits a new `io.jsonwebtoken.Identifiable` interface and its `getId()` - method is preferred over the now-deprecated `getAlgorithmName()` method. This is to guarantee API congruence with - all other JWT-identifiable algorithm names that can be set as a header value. +* `io.jsonwebtoken.CompressionCodec` is now deprecated in favor of the new `io.jsonwebtoken.io.CompressionAlgorithm` + interface. This is to guarantee API congruence with all other JWT-identifiable algorithm IDs that can be set as a + header value. + + +* `io.jsonwebtoken.CompressionCodecResolver` has been deprecated in favor of the new + `JwtParserBuilder#addCompressionAlgorithms` method. #### Breaking Changes +* **`io.jsonwebtoken.Claims` and `io.jsonwebtoken.Header` instances are now immutable** to enhance security and thread + safety. Creation and mutation are supported with newly introduced `ClaimsBuilder` and `HeaderBuilder` concepts. + Even though mutation methods have migrated, there are a couple that have been removed entirely: + * `io.jsonwebtoken.JwsHeader#setAlgorithm` has been removed - the `JwtBuilder` will always set the appropriate + `alg` header automatically based on builder state. + * `io.jsonwebtoken.Header#setCompressionAlgorithm` has been removed - the `JwtBuilder` will always set the appropriate + `zip` header automatically based on builder state. + + * `io.jsonwebtoken.Jwts`'s `header(Map)`, `jwsHeader()` and `jwsHeader(Map)` methods have been removed in favor - of the new `header()` builder-based method to support method chaining and dynamic Header type creation. + of the new `header()` method that returns a `HeaderBuilder` to support method chaining and dynamic `Header` type + creation. The `HeaderBuilder` will dynamically create a `Header`, `JwsHeader` or `JweHeader` automatically based on + builder state. + + +* Similarly, `io.jsonwebtoken.Jwts`'s `claims()` static method has been changed to return a `ClaimsBuilder` instead + of a `Claims` instance. * **JWTs that do not contain JSON Claims now have a payload type of `byte[]` instead of `String`** (that is, @@ -166,19 +185,6 @@ deprecate some concepts, or in some cases, completely break backwards compatibil `resolveSigningKey(JwsHeader, byte[])`. -* **`io.jsonwebtoken.Claims` and `io.jsonwebtoken.Header` instances are now immutable** to enhance security and thread - safety. Creation and mutation are supported with newly introduced `ClaimsBuilder` and `HeaderBuilder` concepts. - - -* Consequently, `io.jsonwebtoken.Jwts`'s `claims()` static method has been changed to return a `ClaimsBuilder` instead - of a `Claims` instance. - - -* Similarly, `io.jsonwebtoken.Jwts`'s `header()` static method has been changed to return a `HeaderBuilder` instead of - a `Header` instance. The `HeaderBuilder` will dynamically create a `Header`, `JwsHeader` or `JweHeader` - automatically based on builder state. - - * `io.jsonwebtoken.JwtParser` is now immutable. All mutation/modification methods (setters, etc) deprecated 4 years ago have been removed. All parser configuration requires using the `JwtParserBuilder` (i.e. `Jwts.parser()`). @@ -191,7 +197,8 @@ deprecate some concepts, or in some cases, completely break backwards compatibil * `io.jsonwebtoken.CompressionCodec` implementations are no longer discoverable via `java.util.ServiceLoader` due to runtime performance problems with the JDK's `ServiceLoader` implementation per - https://github.com/jwtk/jjwt/issues/648. + https://github.com/jwtk/jjwt/issues/648. Custom implementations should be made available to the `JwtParser` via + the new `JwtParserBuilder#addCompressionAlgorithms` method. * Prior to this release, if there was a serialization problem when serializing the JWT Header, an `IllegalStateException` @@ -202,7 +209,7 @@ deprecate some concepts, or in some cases, completely break backwards compatibil * Parsing of unsecured JWTs (`alg` header of `none`) are now disabled by default as mandated by [RFC 7518, Section 3.6](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6). If you require parsing of - unsecured JWTs, you must call the `enableUnsecuredJws` method on the `JwtParserBuilder`, but note the security + unsecured JWTs, you must call the `JwtParserBuilder#enableUnsecured()` method, but note the security implications mentioned in that method's JavaDoc before doing so. diff --git a/README.md b/README.md index 71df86540..dffa0c0db 100644 --- a/README.md +++ b/README.md @@ -149,13 +149,13 @@ enforcement. ## Features - * Fully functional on all JDKs and Android + * Fully functional on all Java 7+ JDKs and Android * Automatic security best practices and assertions * Easy to learn and read API * Convenient and readable [fluent](http://en.wikipedia.org/wiki/Fluent_interface) interfaces, great for IDE auto-completion to write code quickly * Fully RFC specification compliant on all implemented functionality, tested against RFC-specified test vectors - * Stable implementation with over 1,200+ tests and enforced 100% test code coverage. Every single method, statement + * Stable implementation with over 1,100+ tests and enforced 100% test code coverage. Every single method, statement and conditional branch variant in the entire codebase is tested and required to pass on every build. * Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms: @@ -696,9 +696,9 @@ import java.security.Key; // We need a signing key, so we'll create one just for this example. Usually // the key would be read from your application configuration instead. -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); -String jws = Jwts.builder().setSubject("Joe").signWith(key).compact(); +String jws = Jwts.builder().subject("Joe").signWith(key).compact(); ``` How easy was that!? @@ -730,7 +730,7 @@ that pack a punch! > **Note** > > **Type-safe JWTs:** To get a type-safe `Claims` JWT result, call the `parseClaimsJws` method (since there are many -similar methods available). You will get an `UnsupportedJwtException` if you parse your JWT with wrong method.]() +similar methods available). You will get an `UnsupportedJwtException` if you parse your JWT with wrong method. But what if parsing or signature validation failed? You can catch `JwtException` and react accordingly: @@ -755,27 +755,31 @@ Now that we've had a quickstart 'taste' of how to create and parse JWTs, let's c You create a JWT as follows: 1. Use the `Jwts.builder()` method to create a `JwtBuilder` instance. -2. Call builder methods to set the `payload` [content](#jwt-content) or [claims](#jwt-claims) and any - [`header` parameters](#jwt-header-builder) as desired. -3. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT, respectively. -4. Call the `compact()` method to produce the resulting compact JWT string. +2. Optionally set any [`header` parameters](#jwt-header) as desired. +3. Call builder methods to set the payload [content](#jwt-content) or [claims](#jwt-claims). +4. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT. +5. Call the `compact()` method to produce the resulting compact JWT string. For example: ```java String jwt = Jwts.builder() // (1) - .setSubject("Bob") // (2) JSON Claims, or - //.setContent(aByteArray, "text/plain") // any byte[] content, with media type + .header() // (2) optional + .keyId("aKeyId") + .and() - .signWith(signingKey) // (3) if signing, or + .subject("Bob") // (3) JSON Claims, or + //.content(aByteArray, "text/plain") // any byte[] content, with media type + + .signWith(signingKey) // (4) if signing, or //.encryptWith(key, keyAlg, encryptionAlg) // if encrypting - .compact(); // (4) + .compact(); // (5) ``` -* The JWT `payload` may be either `byte[]` content (via `setContent`) _or_ JSON Claims -(such as `setSubject`, `setClaims`, etc), but not both. +* The JWT `payload` may be either `byte[]` content (via `content`) _or_ JSON Claims +(such as `subject`, `claims`, etc), but not both. * Either digital signatures (`signWith`) or encryption (`encryptWith`) may be used, but not both. > **Warning** @@ -792,91 +796,122 @@ relevant to the JWT `payload`. JJWT provides a number of ways of setting the en header parameters (name/value pairs). -#### Header Builder +#### JwtBuilder Header -The easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to call -`JwtBuilder` `setHeader` with `Jwts.headerBuilder()`. For example: +The easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to use the +`JwtBuilder`'s `header()` builder as desired, and then call its `and()` method to return back +to the `JwtBuilder` for further configuration. For example: ```java String jwt = Jwts.builder() - .setHeader(Jwts.headerBuilder() // <---- - .setKeyId("aKeyId") - .setX509Url(aUri) - .put("someName", "anyValue") - .putAll(anotherMap) + .header() // <---- + .keyId("aKeyId") + .x509Url(aUri) + .add("someName", anyValue) + .add(mapValues) // ... etc ... - ) - // ... etc ... + .and() // go back to the JwtBuilder + + .subject("Joe") // resume JwtBuilder calls... + // ... etc ... .compact(); ``` -In addition to type-safe setter methods, `Jwts.headerBuilder()` can also support arbitrary name/value pairs via -`put` and `putAll` as shown above. It can also support automatically calculating -X.509 thumbprints and other builder-style benefits that the other `JwtBuilder` `setHeader`* methods do not support. -For this reason, `Jwts.headerBuilder()` is the recommended way to set a JWT header and is preferred over the other -approaches listed next. +The `JwtBuilder` `header()` builder also supports automatically calculating X.509 thumbprints and other builder-style benefits that +a simple property getter/setter object would not do. > **Note** -> -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. +> +> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will always set them +> automatically as needed. -#### Header Parameters - -Another way of setting header parameters is to call `JwtBuilder` `setHeaderParam` one or more times as needed: +##### Custom Header Parameters +In addition to type-safe builder methods for standard header parameters, `JwtBuilder.header()` can also support +arbitrary name/value pairs via the `add` method: ```java -String jwt = Jwts.builder() +Jwts.builder() + + .header() + .add("aHeaderName", aValue) + // ... etc ... + .and() // return to the JwtBuilder + +// ... etc ... +``` - .setHeaderParam("kid", "myKeyId") - - // ... etc ... + +##### Header Parameter Map +The `add` method is also overloaded to support multiple parameters in a `Map`: +```java +Jwts.builder() + + .header() + .add(multipleHeaderParamsMap) + // ... etc ... + .and() // return to the JwtBuilder + +// ... etc ... ``` -Each time `setHeaderParam` is called, it simply appends the key-value pair to an internal `Header` instance, -potentially overwriting any existing identically-named key/value pair. +#### Jwts HeaderBuilder -The downside with this approach is that you lose any type-safe setter methods or additional builder utility methods -available on the `Jwts.headerBuilder()` such as `setContentType`,`setKeyId`, `withX509Sha256Thumbprint`, etc. +Using `Jwts.builder().header()` shown above is the preferred way to modify a header when using the `JwtBuilder`. -> **Note** -> -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. +However, if you would like to create a 'standalone' `Header` outside of the context of using the `JwtBuilder`, you +can use `Jwts.header()` instead to return an independent `Header` builder. For example: - -#### Header Map +```java +Header header = Jwts.header() + + .keyId("aKeyId") + .x509Url(aUri) + .add("someName", anyValue) + .add(mapValues) + // ... etc ... + + .build() // <---- not 'and()' +``` -If you want to specify the entire header at once, and you don't want to use `Jwts.headerBuilder()`, you can use -`JwtBuilder` `setHeader(Map)` method instead: +There are only two differences between `Jwts.header()` and `Jwts.builder().header()`: +1. `Jwts.header()` builds a 'detached' `Header` that is not associated with any particular JWT, whereas + `Jwts.builder().header()` always modifies the header of the immediate JWT being constructed by its parent + `JwtBuilder`. -```java -Map header = getMyHeaderMap(); //implement me +2. `Jwts.header()` has a `build()` method to produce an explicit `Header` instance and + `Jwts.builder().header()` does not (it has an `and()` method instead) because its parent `JwtBuilder` will implicitly + create the header instance when necessary. -String jwt = Jwts.builder() - .setHeader(header) - +A standalone header might be useful if you want to aggregate common header parameters in a single 'template' +instance so you don't have to repeat them for each `JwtBuilder` usage. Then this 'template' `Header` can be used to +populate `JwtBuilder` usages by just appending it to the `JwtBuilder` header, for example: + +```java +// perhaps somewhere in application configuration: +Header commonHeaders = Jwts.header() + .issuer("My Company") // ... etc ... + .build(); -``` +// -------------------------------- -> **Warning** -> -> Per standard Java `setter` idioms, `setHeader` is a _full replacement_ operation - it will replace any -> and all existing header name/value pairs. +// somewhere else during actual Jwt construction: +String jwt = Jwts.builder() -The downside with this approach is that you lose any type-safe setter methods or additional builder utility methods -available on the `Jwts.headerBuilder()` such as `setContentType`,`setKeyId`, `withX509Sha256Thumbprint`, etc. + .header() + .add(commonHeaders) // <---- + .add("specificHeader", specificValue) // jwt-specific headers... + .and() -> **Note** -> -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. + .subject("whatever") + // ... etc ... + .compact(); +``` ### JWT Payload @@ -887,15 +922,15 @@ especially for representing identity claims. As a result, the `JwtBuilder` supports two distinct payload options: -* `setContent` if you would like the `payload` to be arbitrary byte array content, and -* `setClaims` (and supporting helper methods) if you would like the `payload` to be a JSON Claims `Object`. +* `content` if you would like the payload to be arbitrary byte array content, or +* `claims` (and supporting helper methods) if you would like the payload to be a JSON Claims `Object`. -Either option may be used, but not both. Using both will cause `build()` to throw an exception. +Either option may be used, but not both. Using both will cause `compact()` to throw an exception. #### Arbitrary Content -You can set the JWT `payload` to be any arbitrary byte array content by using the `JwtBuilder` `setContent` method. +You can set the JWT payload to be any arbitrary byte array content by using the `JwtBuilder` `content` method. For example: ```java @@ -903,47 +938,48 @@ byte[] content = "Hello World".getBytes(StandardCharsets.UTF_8); String jwt = Jwts.builder() - .setContent(content, "text/plain") // <--- + .content(content, "text/plain") // <--- // ... etc ... .build(); ``` -Notice this particular example of `setContent` uses the two-argument convenience variant: +Notice this particular example of `content` uses the two-argument convenience variant: 1. The first argument is the actual byte content to set as the JWT payload 2. The second argument is a String identifier of an IANA Media Type. The second argument will cause the `JwtBuilder` to automatically set the `cty` (Content Type) header according to the JWT specification's [recommended compact format](https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10). -This two-argument variant is typically recommended over the single-argument `setContent(byte[])` method because it +This two-argument variant is typically recommended over the single-argument `content(byte[])` method because it guarantees the JWT recipient can inspect the `cty` header to determine how to convert the `payload` byte array into a final form that the application can use. Without setting the `cty` header, the JWT recipient _must_ know via out-of-band (external) information how to process the byte array, which is usually less convenient and always requires code changes if the content format ever changes. -For these reasons, it is strongly recommended to use the two-argument `setContent` method variant. +For these reasons, it is strongly recommended to use the two-argument `content` method variant. #### JWT Claims -Instead of a content byte array, a JWT `payload` may contain assertions or claims for a JWT recipient. In -this case, the `payload` is a 'claims' JSON `Object`, and JJWT supports this with a type-safe `Claims` instance. +Instead of a content byte array, a JWT payload may contain assertions or claims for a JWT recipient. In +this case, the payload is a `Claims` JSON `Object`, and JJWT supports claims creation with type-safe +builder methods. ##### Standard Claims -The `JwtBuilder` provides convenient setter methods for standard registered Claim names defined in the JWT +The `JwtBuilder` provides convenient builder methods for standard registered Claim names defined in the JWT specification. They are: -* `setIssuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1) -* `setSubject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2) -* `setAudience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3) -* `setExpiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4) -* `setNotBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5) -* `setIssuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6) -* `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7) +* `issuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1) +* `subject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2) +* `audience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3) +* `expiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4) +* `notBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5) +* `issuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6) +* `id`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7) For example: @@ -951,13 +987,13 @@ For example: String jws = Jwts.builder() - .setIssuer("me") - .setSubject("Bob") - .setAudience("you") - .setExpiration(expiration) //a java.util.Date - .setNotBefore(notBefore) //a java.util.Date - .setIssuedAt(new Date()) // for example, now - .setId(UUID.randomUUID().toString()) //just an example id + .issuer("me") + .subject("Bob") + .audience("you") + .expiration(expiration) //a java.util.Date + .notBefore(notBefore) //a java.util.Date + .issuedAt(new Date()) // for example, now + .id(UUID.randomUUID().toString()) //just an example id /// ... etc ... ``` @@ -974,65 +1010,32 @@ String jws = Jwts.builder() .claim("hello", "world") // ... etc ... - ``` -Each time `claim` is called, it simply appends the key-value pair to an internal `Claims` instance, potentially +Each time `claim` is called, it simply appends the key-value pair to an internal `Claims` builder, potentially overwriting any existing identically-named key/value pair. Obviously, you do not need to call `claim` for any [standard claim name](#jws-create-claims-standard), and it is -recommended instead to call the standard respective type-safe setter method as this enhances readability. - - -##### Claims Instance - -If you want to specify all claims at once, you can use the `Jwts.claims()` method and build up the claims -with it: - -```java - -Claims claims = Jwts.claims(); - -populate(claims); //implement me - -String jws = Jwts.builder() - - .setClaims(claims) - - // ... etc ... - -``` - -> **Warning** -> -> Per standard Java `setter` idioms, calling `setClaims` will fully replace all existing claim name/value -pairs with the specified values. If you want to add (append) claims in bulk, and not fully replace them, use the -> `JwtBuilder`'s `addClaims` method instead. +recommended instead to call the standard respective type-safe named builder method as this enhances readability. + + ##### Claims Map -If you want to specify all claims at once, and you don't want to use `Jwts.claims()`, you can use `JwtBuilder` -`setClaims(Map)` method instead: +If you want to add multiple claims at once, you can use `JwtBuilder` `claims(Map)` method: ```java -Map claims = getMyClaimsMap(); //implement me +Map claims = getMyClaimsMap(); //implement me String jws = Jwts.builder() - .setClaims(claims) + .claims(claims) // ... etc ... - ``` -> **Warning** -> -> Per standard Java `setter` idioms, calling `setClaims` will fully replace all existing claim name/value -pairs with the specified values. If you want to add (append) claims in bulk, and not fully replace them, use the -> `JwtBuilder`'s `addClaims` method instead. - ### JWT Compression @@ -1048,7 +1051,7 @@ Please see the main [Compression](#compression) section to see how to compress a You read (parse) a JWT as follows: 1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance. -2. Optionally call `setKeyLocator`, `verifyWith` or `decryptWith` methods if you expect to parse [signed](#jws) or [encrypted](#jwe) JWTs. +2. Optionally call `keyLocator`, `verifyWith` or `decryptWith` methods if you expect to parse [signed](#jws) or [encrypted](#jwe) JWTs. 3. Call the `build()` method on the `JwtParserBuilder` to create and return a thread-safe `JwtParser`. 4. Call one of the various `parse*` methods with your compact JWT string, depending on the type of JWT you expect. 5. Wrap the `parse*` call in a try/catch block in case parsing, signature verification, or decryption fails. @@ -1059,19 +1062,19 @@ For example: Jwt jwt; try { - jwt = Jwts.parser() // (1) + jwt = Jwts.parser() // (1) - .setKeyLocator(keyLocator) // (2) dynamically locate signing or encryption keys - //.verifyWith(key) // or a static key used to verify all signed JWTs - //.decryptWith(key) // or a static key used to decrypt all encrypted JWTs + .keyLocator(keyLocator) // (2) dynamically locate signing or encryption keys + //.verifyWith(key) // or a static key used to verify all signed JWTs + //.decryptWith(key) // or a static key used to decrypt all encrypted JWTs - .build() // (3) + .build() // (3) - .parse(compact); // (4) or parseClaimsJws, parseClaimsJwe, parseContentJws, etc + .parse(compact); // (4) or parseClaimsJws, parseClaimsJwe, parseContentJws, etc // we can safely trust the JWT -catch (JwtException ex) { // (5) +catch (JwtException ex) { // (5) // we *cannot* use the JWT as intended by its creator } @@ -1166,7 +1169,7 @@ received, at parse time, so you can't 'hard code' any verification or decryption #### Key Locator If you need to support dynamic key lookup when encountering JWTs, you'll need to implement -the `Locator` interface and specify an instance on the `JwtParserBuilder` via the `setKeyLocator` method. For +the `Locator` interface and specify an instance on the `JwtParserBuilder` via the `keyLocator` method. For example: ```java @@ -1174,7 +1177,7 @@ Locator keyLocator = getMyKeyLocator(); Jwts.parser() - .setKeyLocator(keyLocator) // <---- + .keyLocator(keyLocator) // <---- .build() // ... etc ... @@ -1214,7 +1217,7 @@ String keyId = getKeyId(key); //any mechanism you have to associate a key with a String jws = Jwts.builder() - .header().setKeyId(keyId).and() // <--- add `kid` header + .header().keyId(keyId).and() // <--- add `kid` header .signWith(key) // for JWS //.encryptWith(key, keyAlg, encryptionAlg) // for JWE @@ -1285,7 +1288,7 @@ on the type of JWS or JWE algorithm used. That is: * For JWE direct encryption, the returned decryption key should be a `SecretKey`. * For password-based key derivation algorithms, the returned decryption key should be a `io.jsonwebtoken.security.Password`. You can create a `Password` instance by calling - `Keys.forPassword(char[] passwordCharacters)`. + `Keys.password(char[] passwordCharacters)`. * For asymmetric key management algorithms, the returned decryption key should be a `PrivateKey` (not a `PublicKey`). @@ -1342,14 +1345,14 @@ obvious problems since `exp` and `nbf` are time-based assertions, and clock time assertions. You can account for these differences (usually no more than a few minutes) when parsing using the `JwtParserBuilder`'s -`setAllowedClockSkewSeconds`. For example: +`clockSkewSeconds`. For example: ```java long seconds = 3 * 60; //3 minutes Jwts.parser() - .setAllowedClockSkewSeconds(seconds) // <---- + .clockSkewSeconds(seconds) // <---- // ... etc ... .build() @@ -1362,14 +1365,14 @@ atomic clocks around the world. #### Custom Clock Support -If the above `setAllowedClockSkewSeconds` isn't sufficient for your needs, the timestamps created +If the above `clockSkewSeconds` isn't sufficient for your needs, the timestamps created during parsing for timestamp comparisons can be obtained via a custom time source. Call the `JwtParserBuilder`'s -`setClock` method with an implementation of the `io.jsonwebtoken.Clock` interface. For example: +`clock` method with an implementation of the `io.jsonwebtoken.Clock` interface. For example: ```java Clock clock = new MyClock(); -Jwts.parser().setClock(myClock) //... etc ... +Jwts.parser().clock(myClock) //... etc ... ``` The `JwtParser`'s default `Clock` implementation simply returns `new Date()` to reflect the time when parsing occurs, @@ -1514,10 +1517,10 @@ JWT signature algorithm you might want to use. ##### Secret Keys If you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the respective -algorithm's `keyBuilder()` method: +algorithm's `key()` builder method: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); //or HS384.keyBuilder() or HS512.keyBuilder() +SecretKey key = Jwts.SIG.HS256.key().build(); //or HS384.key() or HS512.key() ``` Under the hood, JJWT uses the JCA default provider's `KeyGenerator` to create a secure-random key with the correct @@ -1527,7 +1530,7 @@ If you want to specify a specific JCA `Provider` or `SecureRandom` to use during as builder arguments. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().setProvider(aProvider).setRandom(aSecureRandom).build(); +SecretKey key = Jwts.SIG.HS256.key().provider(aProvider).random(aSecureRandom).build(); ``` If you need to save this new `SecretKey`, you can Base64 (or Base64URL) encode it: @@ -1544,10 +1547,10 @@ further encrypt it, etc, before saving to disk (for example). ##### Asymmetric Keys If you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA -algorithms, use an algorithm's respective `keyPairBuilder()` method: +algorithms, use an algorithm's respective `keyPair()` builder method: ```java -KeyPair keyPair = Jwts.SIG.RS256.keyPairBuilder().build(); //or RS384, RS512, PS256, etc... +KeyPair keyPair = Jwts.SIG.RS256.keyPair().build(); //or RS384, RS512, PS256, etc... ``` Once you've generated a `KeyPair`, you can use the private key (`keyPair.getPrivate()`) to create a JWS and the @@ -1578,7 +1581,7 @@ For example: ```java String jws = Jwts.builder() // (1) - .setSubject("Bob") // (2) + .subject("Bob") // (2) .signWith(key) // (3) <--- @@ -1693,7 +1696,7 @@ Please see the main [Compression](#compression) section to see how to compress a You read (parse) a JWS as follows: 1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance. -2. Call either [setKeyLocator](#key-locator) or `verifyWith` methods to determine the key used to verify the JWS signature. +2. Call either [keyLocator](#key-locator) or `verifyWith` methods to determine the key used to verify the JWS signature. 3. Call the `build()` method on the `JwtParserBuilder` to return a thread-safe `JwtParser`. 4. Finally, call the `parseClaimsJws(String)` method with your jws `String`, producing the original JWS. 5. The entire call is wrapped in a try/catch block in case parsing or signature validation fails. We'll cover @@ -1705,9 +1708,9 @@ For example: Jws jws; try { - jws = Jwts.parser() // (1) + jws = Jwts.parser() // (1) - .setKeyLocator(keyLocator) // (2) dynamically lookup verification keys based on each JWS + .keyLocator(keyLocator) // (2) dynamically lookup verification keys based on each JWS //.verifyWith(key) // or a static key used to verify all encountered JWSs .build() // (3) @@ -2145,7 +2148,7 @@ For example: ```java String jwe = Jwts.builder() // (1) - .setSubject("Bob") // (2) + .subject("Bob") // (2) .encryptWith(key, keyAlgorithm, encryptionAlgorithm) // (3) @@ -2167,7 +2170,7 @@ its size. Please see the main [Compression](#compression) section to see how to You read (parse) a JWE as follows: 1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance. -2. Call either [setKeyLocator](#key-locator) or `decryptWith` methods to determine the key used to decrypt the JWE. +2. Call either [keyLocator](#key-locator) or `decryptWith` methods to determine the key used to decrypt the JWE. 4. Call the `JwtParserBuilder`'s `build()` method to create a thread-safe `JwtParser`. 5. Parse the jwe string with the `JwtParser`'s `parseClaimsJwe` or `parseContentJwe` method. 6. Wrap the entire call is in a try/catch block in case decryption or integrity verification fails. @@ -2178,9 +2181,9 @@ For example: Jwe jwe; try { - jwe = Jwts.parser() // (1) + jwe = Jwts.parser() // (1) - .setKeyLocator(keyLocator) // (2) dynamically lookup decryption keys based on each JWE + .keyLocator(keyLocator) // (2) dynamically lookup decryption keys based on each JWE //.decryptWith(key) // or a static key used to decrypt all encountered JWEs .build() // (3) @@ -2261,7 +2264,7 @@ If a JWE is compressed using the `DEF` ([DEFLATE](https://www.rfc-editor.org/rfc after decryption, and there is nothing you need to configure. If, however, a custom compression algorithm was used to compress the JWE, you will need to tell the -`JwtParserBuilder` how to resolve your `CompressionCodec` to decompress the JWT. +`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT. Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing. @@ -2287,7 +2290,7 @@ seen for JWTs. You create a JWK as follows: 1. Use the `Jwks.builder()` method to create a `JwkBuilder` instance. -2. Call the `forKey` method with the Java key you wish to represent as a JWK. +2. Call the `key` method with the Java key you wish to represent as a JWK. 3. Call builder methods to set any additional key fields or metadata, such as a `kid` (Key ID), X509 Certificates, etc as desired. 4. Call the `build()` method to produce the resulting JWK. @@ -2295,13 +2298,24 @@ You create a JWK as follows: For example: ```java -SecretKey key = getSecretKey(); // or RSA or EC PublicKey or PrivateKey -SecretJwk = Jwts.builder().forKey(key) // (1) and (2) +SecretKey key = getSecretKey(); // or RSA or EC PublicKey or PrivateKey +SecretJwk = Jwks.builder().key(key) // (1) and (2) - .setId("mySecretKeyId") // (3) + .id("mySecretKeyId") // (3) // ... etc ... - .build(); // (4) + .build(); // (4) +``` + +#### JWK from a Map + +If you have a `Map` of name/value pairs that reflect an existing JWK, you add them and build a type-safe +`Jwk` instance: + +```java +Map jwkValues = getMyJwkMap(); + +Jwk jwk = Jwks.builder().add(jwkValues).build(); ``` @@ -2312,12 +2326,12 @@ You can read/parse a JWK by building a `JwkParser` and parsing the JWK JSON stri ```java String json = getJwkJsonString(); Jwk jwk = Jwks.parser() - //.setProvider(aJcaProvider) // optional - //.deserializeJsonWith(deserializer) // optional - .build() // create the parser - .parse(json); // actually parse the JSON + //.provider(aJcaProvider) // optional + //.deserializer(deserializer) // optional + .build() // create the parser + .parse(json); // actually parse the JSON -Key key = jwk.toKey(); // convert to a Java Key instance +Key key = jwk.toKey(); // convert to a Java Key instance ``` As shown above you can specify a custom JCA Provider or [JSON deserializer](#json) in the same way as the `JwtBuilder`. @@ -2344,9 +2358,9 @@ For example: ```java RSAPrivateKey rsaPrivateKey = getRSAPrivateKey(); // or ECPrivateKey -RsaPrivateJwk jwk = Jwks.builder().forKey(rsaPrivateKey) +RsaPrivateJwk jwk = Jwks.builder().key(rsaPrivateKey) - //.setPublicKey(rsaPublicKey) // optional, but recommended to avoid extra computation work + //.publicKey(rsaPublicKey) // optional, but recommended to avoid extra computation work .build(); ``` @@ -2359,22 +2373,22 @@ If you have a Java `KeyPair` instance, then you have both the public and private ```java KeyPair rsaKeyPair = getRSAKeyPair(); -RsaPrivateJwk rsaPrivJwk = Jwks.builder().forRsaKeyPair(rsaKeyPair).build(); +RsaPrivateJwk rsaPrivJwk = Jwks.builder().rsaKeyPair(rsaKeyPair).build(); KeyPair ecKeyPair = getECKeyPair(); -EcPrivateJwk ecPrivJwk = Jwks.builder().forEcKeyPair(ecKeyPair).build(); +EcPrivateJwk ecPrivJwk = Jwks.builder().ecKeyPair(ecKeyPair).build(); KeyPair edEcKeyPair = getEdECKeyPair(); -OctetPrivateJwk edEcPrivJwk = Jwks.builder().forOctetKeyPair(edEcKeyPair).build(); +OctetPrivateJwk edEcPrivJwk = Jwks.builder().octetKeyPair(edEcKeyPair).build(); ``` Note that: -* An exception will thrown when calling `forRsaKeyPair` if the specified `KeyPair` instance does not contain +* An exception will thrown when calling `rsaKeyPair` if the specified `KeyPair` instance does not contain `RSAPublicKey` and `RSAPrivateKey` instances. -* Similarly, an exception will be thrown when calling `forEcKeyPair` if +* Similarly, an exception will be thrown when calling `ecKeyPair` if the `KeyPair` instance does not contain `ECPublicKey` and `ECPrivateKey` instances. * Finally, an exception will be -thrown when calling `forOctetKeyPair` if the `KeyPair` instance does not contain X25519, X448, Ed25519, or Ed448 keys +thrown when calling `octetKeyPair` if the `KeyPair` instance does not contain X25519, X448, Ed25519, or Ed448 keys (introduced in JDK 11 and 15 or when using BouncyCastle). @@ -2384,7 +2398,7 @@ Because private JWKs contain public key material, you can always obtain the priv Java `PublicKey` or `KeyPair`. For example: ```java -RsaPrivateJwk privateJwk = Jwks.builder().forKey(rsaPrivateKey).build(); // or ecPrivateKey or edEcPrivateKey +RsaPrivateJwk privateJwk = Jwks.builder().key(rsaPrivateKey).build(); // or ecPrivateKey or edEcPrivateKey // Get the matching public JWK and/or PublicKey: RsaPublicJwk pubJwk = privateJwk.toPublicJwk(); // JWK instance @@ -2411,14 +2425,15 @@ Jwk jwk = Jwks.builder(). /* ... */ .build(); JwkThumbprint sha256Thumbprint = jwk.thumbprint(); // SHA-256 thumbprint by default -JwkThumbprint anotherThumbprint = jwk.thumbprint(hashAlg); // thumbprint using specified hash algorithm +JwkThumbprint anotherThumbprint = jwk.thumbprint(Jwks.HASH.SHA512); // or a specified hash algorithm ``` The resulting `JwkThumbprint` instance provides some useful methods: * `jwkThumbprint.toByteArray()`: the thumbprint's actual digest bytes - i.e. the raw output from the hash algorithm * `jwkThumbprint.toString()`: the digest bytes as a Base64URL-encoded string -* `jwkThumbprint.getHashAlgorithm()`: the specific `HashAlgorithm` used to compute the thumbprint +* `jwkThumbprint.getHashAlgorithm()`: the specific `HashAlgorithm` used to compute the thumbprint. Many standard IANA + hash algorithms are available as constants in the `Jwts.HASH` utility class. * `jwkThumbprint.toURI()`: the thumbprint's canonical URI as defined by the [JWK Thumbprint URI](https://www.rfc-editor.org/rfc/rfc9278.html) specification @@ -2444,17 +2459,17 @@ String kid = jwk.thumbprint().toString(); jwk.setId(kid) // Jwks are immutable - there is no `setId` method ``` -Instead, you may use the `setIdFromThumbprint` methods on the `JwkBuilder` when creating a `Jwk`: +Instead, you may use the `idFromThumbprint` methods on the `JwkBuilder` when creating a `Jwk`: ```java -Jwk jwk = Jwks.builder().forKey(aKey) +Jwk jwk = Jwks.builder().key(aKey) - .setIdFromThumbprint() // or setIdFromThumbprint(hashAlgorithm) + .idFromThumbprint() // or idFromThumbprint(HashAlgorithm) .build(); ``` -Calling either `setIdFromThumbprint` method will ensure that calling `jwk.getId()` equals `thumbprint.toString()` +Calling either `idFromThumbprint` method will ensure that calling `jwk.getId()` equals `thumbprint.toString()` (which is `Encoders.BASE64URL.encode(thumbprint.toByteArray())`). @@ -2531,10 +2546,13 @@ This is true for all secret or private key members in `SecretJwk` and `PrivateJw ## Compression -**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) however JJWT supports it for JWS -(Signed JWTs) as well**. If you are positive that a JWT you create with JJWT -will _also_ be parsed with JJWT, you can use this feature with both JWEs and JWSs, otherwise it is best to only use it -for JWEs. +> **Warning** +> +> **The JWT specifications tandardizes compression for JWEs (Encrypted JWTs) ONLY, however JJWT supports it for JWS +> (Signed JWTs) as well**. +> +> If you are positive that a JWT you create with JJWT will _also_ be parsed with JJWT, +> you can use this feature with both JWEs and JWSs, otherwise it is best to only use it for JWEs. If a JWT's `payload` is sufficiently large - that is, it is a large content byte array or JSON with a lot of name/value pairs (or individual values are very large or verbose) - you can reduce the size of the compact JWT by @@ -2548,96 +2566,60 @@ If you want to compress your JWT, you can use the `JwtBuilder`'s `compressWith( example: ```java - Jwts.builder() +Jwts.builder() - .compressWith(CompressionCodecs.DEFLATE) // or CompressionCodecs.GZIP + .compressWith(Jwts.ZIP.DEF) // DEFLATE compression algorithm // .. etc ... ``` -If you use the `DEFLATE` or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during -parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress the payload as -expected. - -> **Note** -> -> JJWT does not support compression for Unprotected JWTs because they are susceptible to various compression -> vulnerability attacks (memory exhaustion, denial of service, etc.). +If you use any of the algorithm constants in the `Jwts.ZIP` class, that's it, you're done. You don't have to +do anything during parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress +the payload as expected. -### Custom Compression Codec - -If the default `DEFLATE` or `GZIP` compression codecs are not suitable for your needs, you can create your own -`CompressionCodec` implementation(s). +### Custom Compression Algorithm -Just as you would with the default codecs, you may specify that you want a JWT compressed by calling the `JwtBuilder`'s -`compressWith` method, supplying your custom implementation instance. When you call `compressWith`, the JWT `payload` -will be compressed with your algorithm, and the -[`zip` (Compression Algorithm)](https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3) -header will automatically be set to the value returned by your codec's `getId()` method as specified in the JWT -specification. +If the default `Jwts.ZIP` compression algorithms are not suitable for your needs, you can create your own +`CompressionAlgorithm` implementation(s). -However, the `JwtParser` needs to be aware of this custom codec as well, so it can use it while parsing. You do this -by calling the `JwtParserBuilder`'s `addCompressionCodecs` method. For example: +Just as you would with the default algorithms, you may specify that you want a JWT compressed by calling the +`JwtBuilder`'s `compressWith` method, supplying your custom implementation instance. For example: ```java -CompressionCodec myCodec = new MyCompressionCodec(); - -Jwts.parser() - - .addCompressionCodecs(Collections.of(myCodec)) // <---- - - // .. etc ... -``` - -This adds additional `CompressionCodec` implementations to the parser's overall total set of supported codecs (which -already includes the `DEFLATE` and `GZIP` codecs by default). - -The parser will then automatically check to see if the JWT `zip` header has been set to see if a compression codec -algorithm has been used to compress the JWT. If set, the parser will automatically look up your `CompressionCodec` by -its `getId()` value, and use it to decompress the JWT. - - -### Compression Codec Locator - -If for some reason the default `addCompressionCodecs` method and lookup-by-id behavior already supported by the -`JwtParserBuilder` is not sufficient for your needs, you can implement your own `Locator` to look -up the codec. +CompressionAlgorithm myAlg = new MyCompressionAlgorithm(); -Typically, a `Locator` implementation will inspect the `zip` header to find out what algorithm was -used and then return a codec instance that supports that algorithm. For example: - -```java -public class MyCompressionCodecLocator implements Locator { - - @Override - public CompressionCodec locate(Header header) { - - String id = header.getCompressionAlgorithm(); // 'zip' header - - CompressionCodec codec = getCompressionCodec(id); //implement me - - return codec; - } -} +Jwts.builder() + + .compressWith(myAlg) // <---- + + // .. etc ... ``` -Your custom `Locator` can then inspect any other header as necessary. +When you call `compressWith`, the JWT `payload` will be compressed with your algorithm, and the +[`zip` (Compression Algorithm)](https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3) +header will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as +required by the JWT specification. -You then provide your custom `Locator` to the `JwtParserBuilder` as follows: +However, the `JwtParser` needs to be aware of this custom algorithm as well, so it can use it while parsing. You do this +by calling the `JwtParserBuilder`'s `addCompressionAlgorithms` method. For example: ```java -Locator myCodecLocator = new MyCompressionCodecLocator(); +CompressionAlgorithm myAlg = new MyCompressionAlgorithm(); Jwts.parser() - .setCompressionCodecLocator(myCodecLocator) // <---- + .addCompressionAlgorithms(Collections.of(myAlg)) // <---- // .. etc ... ``` -Again, this is only necessary if the JWT-standard `zip` header lookup default behavior already supported by the -`JwtParser` is not sufficient. +This adds additional `CompressionAlgorithm` implementations to the parser's overall total set of supported compression +algorithms (which already includes all of the `Jwts.ZIP` algorithms by default). + +The parser will then automatically check to see if the JWT `zip` header has been set to see if a compression +algorithm has been used to compress the JWT. If set, the parser will automatically look up your +`CompressionAlgorithm` by its `getId()` value, and use it to decompress the JWT. ## JSON Support @@ -2684,7 +2666,7 @@ Serializer> serializer = getMySerializer(); //implement me Jwts.builder() - .serializeToJsonWith(serializer) + .serializer(serializer) // ... etc ... ``` @@ -2696,7 +2678,7 @@ Deserializer> deserializer = getMyDeserializer(); //implement me Jwts.parser() - .deserializeJsonWith(deserializer) + .deserializer(deserializer) // ... etc ... ``` @@ -2744,7 +2726,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me String jws = Jwts.builder() - .serializeToJsonWith(new JacksonSerializer(objectMapper)) + .serializer(new JacksonSerializer(objectMapper)) // ... etc ... ``` @@ -2756,7 +2738,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me Jwts.parser() - .deserializeJsonWith(new JacksonDeserializer(objectMapper)) + .deserializer(new JacksonDeserializer(objectMapper)) // ... etc ... ``` @@ -2764,7 +2746,9 @@ Jwts.parser() #### Parsing of Custom Claim Types -By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in through a constructor. For example: +By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to +deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in +through a constructor. For example: ```java new JacksonDeserializer(Maps.of("user", User.class).build()) @@ -2788,7 +2772,7 @@ The `User` object could be retrieved from the `user` claim with the following co ```java Jwts.parser() - .deserializeJsonWith(new JacksonDeserializer(Maps.of("user", User.class).build())) // <----- + .deserializer(new JacksonDeserializer(Maps.of("user", User.class).build())) // <----- .build() @@ -2863,7 +2847,7 @@ Gson gson = new GsonBuilder() String jws = Jwts.builder() - .serializeToJsonWith(new GsonSerializer(gson)) + .serializer(new GsonSerializer(gson)) // ... etc ... ``` @@ -2875,7 +2859,7 @@ Gson gson = getGson(); //implement me Jwts.parser() - .deserializeJsonWith(new GsonDeserializer(gson)) + .deserializer(new GsonDeserializer(gson)) // ... etc ... ``` @@ -3010,26 +2994,26 @@ information. ### Custom Base64 If for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder` -`base64UrlEncodeWith` method to set the encoder: +`encoder` method to set the encoder: ```java -Encoder base64UrlEncoder = getMyBase64UrlEncoder(); //implement me +Encoder encoder = getMyBase64UrlEncoder(); //implement me String jws = Jwts.builder() - .base64UrlEncodeWith(base64UrlEncoder) + .encoder(encoder) // ... etc ... ``` -and the `JwtParserBuilder`'s `base64UrlDecodeWith` method to set the decoder: +and the `JwtParserBuilder`'s `decoder` method to set the decoder: ```java -Decoder base64UrlDecoder = getMyBase64UrlDecoder(); //implement me +Decoder decoder = getMyBase64UrlDecoder(); //implement me Jwts.parser() - .base64UrlDecodeWith(base64UrlEncoder) + .decoder(decoder) // ... etc ... ``` @@ -3069,13 +3053,13 @@ Example: ```java // Create a test key suitable for the desired HMAC-SHA algorithm: MacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256 -SecretKey key = alg.keyBuilder().build(); +SecretKey key = alg.key().build(); String message = "Hello World!"; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWS: -String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); +String jws = Jwts.builder().content(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); @@ -3096,10 +3080,10 @@ public key: ```java // Create a test key suitable for the desired RSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc... -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his RSA private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's RSA private key .compact(); @@ -3127,10 +3111,10 @@ public key: ```java // Create a test key suitable for the desired ECDSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384 -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his EC private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's EC private key .compact(); @@ -3171,10 +3155,10 @@ using Bob's Edwards Curve public key: ```java // Create a test key suitable for the EdDSA signature algorithm using Ed25519 or Ed448 keys: SignatureAlgorithm alg = Jwts.SIG.Ed25519; //or Ed448 -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his Edwards Curve private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's Edwards Curve private key .compact(); @@ -3211,13 +3195,13 @@ Example: // Create a test key suitable for the desired payload encryption algorithm: // (A*GCM algorithms are recommended, but require JDK >= 8 or BouncyCastle) AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A128GCM, A192GCM, A256CBC-HS512, etc... -SecretKey key = enc.keyBuilder().build(); +SecretKey key = enc.key().build(); String message = "Live long and prosper."; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWE: -String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); +String jwe = Jwts.builder().content(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); @@ -3239,7 +3223,7 @@ decrypt the JWT using her RSA private key: ```java // Create a test KeyPair suitable for the desired RSA key algorithm: -KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.RS512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP or RSA1_5 @@ -3247,7 +3231,7 @@ KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP o AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Bob creates the compact JWE with Alice's RSA public key so only she may read it: -String jwe = Jwts.builder().setAudience("Alice") +String jwe = Jwts.builder().audience("Alice") .encryptWith(pair.getPublic(), alg, enc) // <-- Alice's RSA public key .compact(); @@ -3276,13 +3260,13 @@ efficient than the `A*KW` variants, but they do require JDK 8 or later (or JDK 7 ```java // Create a test SecretKey suitable for the desired AES Key Wrap algorithm: SecretKeyAlgorithm alg = Jwts.KEY.A256GCMKW; //or A192GCMKW, A128GCMKW, A256KW, etc... -SecretKey key = alg.keyBuilder().build(); +SecretKey key = alg.key().build(); // Chooose the Encryption Algorithm used to encrypt the payload: AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Create the compact JWE: -String jwe = Jwts.builder().setIssuer("me").encryptWith(key, alg, enc).compact(); +String jwe = Jwts.builder().issuer("me").encryptWith(key, alg, enc).compact(); // Parse the compact JWE: String issuer = Jwts.parser().decryptWith(key).build() @@ -3307,7 +3291,7 @@ Alice can then decrypt the JWT using her Elliptic Curve private key: ```java // Create a test KeyPair suitable for the desired EC key algorithm: -KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.ES512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc. @@ -3315,7 +3299,7 @@ KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A19 AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Bob creates the compact JWE with Alice's EC public key so only she may read it: -String jwe = Jwts.builder().setAudience("Alice") +String jwe = Jwts.builder().audience("Alice") .encryptWith(pair.getPublic(), alg, enc) // <-- Alice's EC public key .compact(); @@ -3343,7 +3327,7 @@ as shown below. ```java //DO NOT use this example password in a real app, it is well-known to password crackers: String pw = "correct horse battery staple"; -Password password = Keys.forPassword(pw.toCharArray()); +Password password = Keys.password(pw.toCharArray()); // Choose the desired PBES2 key derivation algorithm: KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_HS384_A192KW or PBES2_HS256_A128KW @@ -3360,9 +3344,9 @@ KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_H AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Create the compact JWE: -String jwe = Jwts.builder().setIssuer("me") +String jwe = Jwts.builder().issuer("me") // Optional work factor is specified in the header: - //.header().setPbes2Count(pbkdf2Iterations)).and() + //.header().pbes2Count(pbkdf2Iterations)).and() .encryptWith(password, alg, enc) .compact(); @@ -3379,8 +3363,8 @@ assert "me".equals(issuer); Example creating and parsing a secret JWK: ```java -SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 -SecretJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +SecretKey key = Jwts.SIG.HS512.key().build(); // or HS384 or HS256 +SecretJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3399,8 +3383,8 @@ assert jwk.equals(parsed); Example creating and parsing an RSA Public JWK: ```java -RSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); -RsaPublicJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +RSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPair().build().getPublic(); +RsaPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3419,11 +3403,11 @@ assert jwk.equals(parsed); Example creating and parsing an RSA Private JWK: ```java -KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.RS512.keyPair().build(); RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); -RsaPrivateJwk privJwk = Jwks.builder().forKey(privKey).setIdFromThumbprint().build(); +RsaPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build(); RsaPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -3445,8 +3429,8 @@ assert privJwk.equals(parsed); Example creating and parsing an Elliptic Curve Public JWK: ```java -ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); -EcPublicJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPair().build().getPublic(); +EcPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3465,11 +3449,11 @@ assert jwk.equals(parsed); Example creating and parsing an Elliptic Curve Private JWK: ```java -KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.ES512.keyPair().build(); ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); -EcPrivateJwk privJwk = Jwks.builder().forKey(privKey).setIdFromThumbprint().build(); +EcPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build(); EcPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -3493,8 +3477,8 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPublicJwk` interface names): ```java -PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); -OctetPublicJwk jwk = builder().forOctetKey(key).setIdFromThumbprint().build(); +PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); +OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3515,11 +3499,11 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPrivateJwk` and `OctetPublicJwk` interface names): ```java -KeyPair pair = Jwts.SIG.Ed448.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); -OctetPrivateJwk privJwk = builder().forOctetKey(privKey).setIdFromThumbprint().build(); +OctetPrivateJwk privJwk = builder().octetKey(privKey).idFromThumbprint().build(); OctetPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java index 70a4718e8..0c5829ee1 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java @@ -33,27 +33,66 @@ public interface ClaimsMutator> { * * @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #issuer(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setIssuer(String iss); + /** + * Sets the JWT + * iss (issuer) value. A {@code null} value will remove the property from the JSON map. + * + * @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T issuer(String iss); + /** * Sets the JWT * sub (subject) value. A {@code null} value will remove the property from the JSON map. * * @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #subject(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setSubject(String sub); + /** + * Sets the JWT + * sub (subject) value. A {@code null} value will remove the property from the JSON map. + * + * @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T subject(String sub); + /** * Sets the JWT * aud (audience) value. A {@code null} value will remove the property from the JSON map. * * @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #audience(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setAudience(String aud); + /** + * Sets the JWT + * aud (audience) value. A {@code null} value will remove the property from the JSON map. + * + * @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T audience(String aud); + /** * Sets the JWT * exp (expiration) timestamp. A {@code null} value will remove the property from the JSON map. @@ -62,9 +101,24 @@ public interface ClaimsMutator> { * * @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #expiration(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setExpiration(Date exp); + /** + * Sets the JWT + * exp (expiration) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained after this timestamp should not be used.

+ * + * @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T expiration(Date exp); + /** * Sets the JWT * nbf (not before) timestamp. A {@code null} value will remove the property from the JSON map. @@ -73,9 +127,24 @@ public interface ClaimsMutator> { * * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #notBefore(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setNotBefore(Date nbf); + /** + * Sets the JWT + * nbf (not before) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained before this timestamp should not be used.

+ * + * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T notBefore(Date nbf); + /** * Sets the JWT * iat (issued at) timestamp. A {@code null} value will remove the property from the JSON map. @@ -84,9 +153,24 @@ public interface ClaimsMutator> { * * @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #issuedAt(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setIssuedAt(Date iat); + /** + * Sets the JWT + * iat (issued at) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

The value is the timestamp when the JWT was created.

+ * + * @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T issuedAt(Date iat); + /** * Sets the JWT * jti (JWT ID) value. A {@code null} value will remove the property from the JSON map. @@ -97,6 +181,23 @@ public interface ClaimsMutator> { * * @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #id(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setId(String jti); + + /** + * Sets the JWT + * jti (JWT ID) value. A {@code null} value will remove the property from the JSON map. + * + *

This value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a + * manner that ensures that there is a negligible probability that the same value will be accidentally + * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

+ * + * @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T id(String jti); } diff --git a/api/src/main/java/io/jsonwebtoken/Header.java b/api/src/main/java/io/jsonwebtoken/Header.java index a3e0ee20b..ea28b7a93 100644 --- a/api/src/main/java/io/jsonwebtoken/Header.java +++ b/api/src/main/java/io/jsonwebtoken/Header.java @@ -54,12 +54,16 @@ public interface Header extends Map { /** * JWT {@code Type} header parameter name: "typ" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getType()}. */ + @Deprecated String TYPE = "typ"; /** * JWT {@code Content Type} header parameter name: "cty" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getContentType()}. */ + @Deprecated String CONTENT_TYPE = "cty"; /** @@ -67,12 +71,16 @@ public interface Header extends Map { * * @see JWS Algorithm Header * @see JWE Algorithm Header + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()}. */ + @Deprecated String ALGORITHM = "alg"; /** * JWT {@code Compression Algorithm} header parameter name: "zip" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCompressionAlgorithm()} */ + @Deprecated String COMPRESSION_ALGORITHM = "zip"; /** diff --git a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java index 180b2e70c..ae1ff568a 100644 --- a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java @@ -25,14 +25,41 @@ */ public interface HeaderMutator> extends MapMutator { + //IMPLEMENTOR NOTE: if this `algorithm` method ever needs to be exposed in the public API, it might be better to + // have it in the Jwts.HeaderBuilder interface and NOT this one: in the context of + // JwtBuilder.Header, there is never a reason for an application developer to call algorithm(id) + // directly because the KeyAlgorithm or SecureDigestAlgorithm instance must always be provided + // via the signWith or encryptWith methods. The JwtBuilder will always set the algorithm + // header based on these two instances, so there is no need for an app dev to do so. + /* + * Sets the JWT {@code alg} (Algorithm) header value. A {@code null} value will remove the property + * from the JSON map. + *
    + *
  • If the JWT is a Signed JWT (a JWS), the + * {@code alg} (Algorithm) header + * parameter identifies the cryptographic algorithm used to secure the JWS.
  • + *
  • If the JWT is an Encrypted JWT (a JWE), the + * alg (Algorithm) header parameter + * identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content + * Encryption Key (CEK). The encrypted content is not usable if the alg value does not represent a + * supported algorithm, or if the recipient does not have a key that can be used with that algorithm.
  • + *
+ * + * @param alg the {@code alg} header value + * @return this header for method chaining + * @since JJWT_RELEASE_VERSION + * + T algorithm(String alg); + */ + /** * Sets the JWT * typ (Type) header value. A {@code null} value will remove the property from the JSON map. * * @param typ the JWT JOSE {@code typ} header value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. + * @return the instance for method chaining. */ - T setType(String typ); + T type(String typ); /** * Sets the JWT @@ -57,46 +84,42 @@ public interface HeaderMutator> extends MapMutatorexample;part="1/2".

* * @param cty the JWT JOSE {@code cty} header value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. + * @return the instance for method chaining. */ - T setContentType(String cty); + T contentType(String cty); /** - * Sets the JWT {@code alg} (Algorithm) header value. A {@code null} value will remove the property - * from the JSON map. - *
    - *
  • If the JWT is a Signed JWT (a JWS), the - * {@code alg} (Algorithm) header - * parameter identifies the cryptographic algorithm used to secure the JWS.
  • - *
  • If the JWT is an Encrypted JWT (a JWE), the - * alg (Algorithm) header parameter - * identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content - * Encryption Key (CEK). The encrypted content is not usable if the alg value does not represent a - * supported algorithm, or if the recipient does not have a key that can be used with that algorithm.
  • - *
+ * Deprecated since of JJWT_RELEASE_VERSION, delegates to {@link #type(String)}. * - * @param alg the {@code alg} header value - * @return this header for method chaining - * @since JJWT_RELEASE_VERSION + * @param typ the JWT JOSE {@code typ} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see #type(String) + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #type(String)} method. + * This method will be removed before the 1.0 release. */ - T setAlgorithm(String alg); + @Deprecated + T setType(String typ); /** - * Sets the JWT zip - * (Compression Algorithm) header parameter value. A {@code null} value will remove - * the property from the JSON map. - * - *

Compatibility Note

+ * Deprecated as of JJWT_RELEASE_VERSION, delegates to {@link #contentType(String)}. * - *

While the JWT family of specifications only defines the zip header in the JWE - * (JSON Web Encryption) specification, JJWT will also support compression for JWS as well if you choose to use it. - * However, be aware that if you use compression when creating a JWS token, other libraries may not be able to - * parse the JWS. However, Compression when creating JWE tokens should be universally accepted for any library - * that supports JWE.

+ * @param cty the JWT JOSE {@code cty} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see #contentType(String) + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #contentType(String)}. + */ + @Deprecated + T setContentType(String cty); + + /** + * Deprecated as of JJWT_RELEASE_VERSION, there is no need to set this any longer as the {@code JwtBuilder} will + * always set the {@code zip} header as necessary. * * @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. + * @return the instance for method chaining. * @since 0.6.0 + * @deprecated since JJWT_RELEASE_VERSION and will be removed before the 1.0 release. */ + @Deprecated T setCompressionAlgorithm(String zip); } diff --git a/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java index 7382faa3d..d118c7374 100644 --- a/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java @@ -37,7 +37,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyUInfo(byte[] info); + T agreementPartyUInfo(byte[] info); /** * Sets any information about the JWE producer for use with key agreement algorithms. A {@code null} value removes @@ -45,7 +45,7 @@ public interface JweHeaderMutator> extends Protect * *

If not {@code null}, this is a convenience method that calls the equivalent of the following:

*
-     * {@link #setAgreementPartyUInfo(byte[]) setAgreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8))
+ * {@link #agreementPartyUInfo(byte[]) agreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8)) * * @param info information about the JWE producer to use with key agreement algorithms. * @return the header for method chaining. @@ -55,7 +55,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyUInfo(String info); + T agreementPartyUInfo(String info); /** * Sets any information about the JWE recipient for use with key agreement algorithms. A {@code null} value removes @@ -69,7 +69,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyVInfo(byte[] info); + T agreementPartyVInfo(byte[] info); /** * Sets any information about the JWE recipient for use with key agreement algorithms. A {@code null} value removes @@ -77,7 +77,7 @@ public interface JweHeaderMutator> extends Protect * *

If not {@code null}, this is a convenience method that calls the equivalent of the following:

*
-     * {@link #setAgreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8))
+ * {@link #agreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8)) * * @param info information about the JWE recipient to use with key agreement algorithms. * @return the header for method chaining. @@ -87,7 +87,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyVInfo(String info); + T agreementPartyVInfo(String info); /** * Sets the number of PBKDF2 iterations necessary to derive the key used during JWE encryption. If this value @@ -112,5 +112,5 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#PBES2_HS512_A256KW * @see OWASP PBKDF2 Iteration Recommendations */ - T setPbes2Count(int count); + T pbes2Count(int count); } diff --git a/api/src/main/java/io/jsonwebtoken/JwsHeader.java b/api/src/main/java/io/jsonwebtoken/JwsHeader.java index 676304259..08a2e704f 100644 --- a/api/src/main/java/io/jsonwebtoken/JwsHeader.java +++ b/api/src/main/java/io/jsonwebtoken/JwsHeader.java @@ -24,46 +24,73 @@ public interface JwsHeader extends ProtectedHeader { /** * JWS Algorithm Header name: the string literal alg + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()} */ + @Deprecated String ALGORITHM = "alg"; /** * JWS JWK Set URL Header name: the string literal jku + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwkSetUrl()} */ + @Deprecated String JWK_SET_URL = "jku"; /** * JWS JSON Web Key Header name: the string literal jwk + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwk()} */ + @Deprecated String JSON_WEB_KEY = "jwk"; /** * JWS Key ID Header name: the string literal kid + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getKeyId()} */ + @Deprecated String KEY_ID = "kid"; /** * JWS X.509 URL Header name: the string literal x5u + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509Url()} */ + @Deprecated String X509_URL = "x5u"; /** * JWS X.509 Certificate Chain Header name: the string literal x5c + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateChain()} */ + @Deprecated String X509_CERT_CHAIN = "x5c"; /** * JWS X.509 Certificate SHA-1 Thumbprint Header name: the string literal x5t + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha1Thumbprint()} */ + @Deprecated String X509_CERT_SHA1_THUMBPRINT = "x5t"; /** * JWS X.509 Certificate SHA-256 Thumbprint Header name: the string literal x5t#S256 + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha256Thumbprint()} */ + @Deprecated String X509_CERT_SHA256_THUMBPRINT = "x5t#S256"; /** * JWS Critical Header name: the string literal crit + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCritical()} */ + @Deprecated String CRITICAL = "crit"; } diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 8501e3efe..2fafd3930 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -20,6 +20,7 @@ import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoder; import io.jsonwebtoken.io.Serializer; +import io.jsonwebtoken.lang.MapMutator; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.KeyAlgorithm; @@ -55,7 +56,7 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setProvider(Provider provider); + JwtBuilder provider(Provider provider); /** * Sets the {@link SecureRandom} to use during cryptographic signing or encryption operations, or {@code null} if @@ -66,95 +67,125 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setSecureRandom(SecureRandom secureRandom); + JwtBuilder random(SecureRandom secureRandom); /** - * Returns the {@link JwtBuilder.Header} to use to modify the constructed JWT's header name/value pairs as desired. - * When finished, callers may return to JWT construction via the {@link JwtBuilder.Header#and() and()} method. + * Returns the {@code Header} to use to modify the constructed JWT's header name/value pairs as desired. + * When finished, callers may return to JWT construction via the {@link BuilderHeader#and() and()} method. * For example: * *
      * String jwt = Jwts.builder()
      *
      *     .header()
-     *         .setKeyId("keyId")
-     *         .set(myHeaderMap)
-     *         // ... other header params ...
-     *         .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder
+     *         .keyId("keyId")
+     *         .add("aName", aValue)
+     *         .add(myHeaderMap)
+     *         // ... etc ...
+     *         .{@link BuilderHeader#and() and()} //return back to the JwtBuilder
      *
-     *     .setSubject("Joe") // resume JwtBuilder calls
+     *     .subject("Joe") // resume JwtBuilder calls
      *     // ... etc ...
      *     .compact();
* - * @return the {@link JwtBuilder.Header} to use for header construction. + * @return the {@link BuilderHeader} to use for header construction. * @since JJWT_RELEASE_VERSION */ - JwtBuilder.Header header(); + BuilderHeader header(); /** - * Sets (and replaces) any existing header with the specified name/value pairs. If you do not want to replace the - * existing header and only want to append to it, call - * {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} - * instead. + * Per standard Java idiom 'setter' conventions, this method sets (and fully replaces) any existing header with the + * specified name/value pairs. This is a wrapper method for: + * + *
+     * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}
+ * + *

If you do not want to replace the existing header and only want to append to it, + * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} instead.

* * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} + * (to replace all header parameters) or + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} + * to only append the {@code map} entries. This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated JwtBuilder setHeader(Map map); /** - * Applies the specified name/value pairs to the header. If a header does not yet exist at the time this method - * is called, one will be created automatically before applying the name/value pairs. + * Adds the specified name/value pairs to the header. Any parameter with an empty or null value will remove the + * entry from the header. This is a wrapper method for: + *
+     * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}
* * @param params the header name/value pairs to append to the header. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated JwtBuilder setHeaderParams(Map params); /** - * Applies the specified name/value pair to the header. If a header does not yet exist at the time this method - * is called, one will be created automatically before applying the name/value pair. + * Adds the specified name/value pair to the header. If the value is {@code null} or empty, the parameter will + * be removed from the header entirely. This is a wrapper method for: + *
+     * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()}
* * @param name the header parameter name * @param value the header parameter value * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated JwtBuilder setHeaderParam(String name, Object value); /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the - * {@link Header#setContentType(String) contentType} header value so the JWT recipient may inspect that value to + * {@link BuilderHeader#contentType(String) contentType} header value so the JWT recipient may inspect that value to * determine how to convert the byte array to the final data type as desired. In this case, consider using - * {@link #setContent(byte[], String)} instead. + * {@link #content(byte[], String)} instead. * - *

This is a convenience method that is effectively the same as:

+ *

This is a wrapper method for:

*
-     * {@link #setContent(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));
+ * {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8)); * - *

If you want the JWT payload to be JSON, use the - * {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead.

+ *

If you want the JWT payload to be JSON, use the {@link #claims()} method instead.

* - *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ *

This method is mutually exclusive of the {@link #claims()} and {@link #claim(String, Object)} + * methods. Either {@code claims} or {@code content}/{@code payload} method variants may be used, but not both.

* * @param payload the string used to set UTF-8-encoded bytes as the JWT payload. * @return the builder for method chaining. - * @see #setContent(byte[]) - * @see #setContent(byte[], String) - * @deprecated since JJWT_RELEASE VERSION in favor of {@link #setContent(byte[])} or {@link #setContent(byte[], String)} + * @see #content(byte[]) + * @see #content(byte[], String) + * @deprecated since JJWT_RELEASE VERSION in favor of {@link #content(byte[])} or {@link #content(byte[], String)} * because both Claims and Content are technically 'payloads', so this method name is misleading. This method will * be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setPayload(String payload); /** * Sets the JWT payload to be the specified content byte array. * + *

This method is mutually exclusive of the {@link #claims()} and {@link #claim(String, Object)} + * methods. Either {@code claims} or {@code content} method variants may be used, but not both.

+ * *

Content Type Recommendation

* *

Unless you are confident that the JWT recipient will always know how to use * the given byte array without additional metadata, it is strongly recommended to use the - * {@link #setContent(byte[], String)} method instead of this one. That method ensures that a JWT recipient + * {@link #content(byte[], String)} method instead of this one. That method ensures that a JWT recipient * can inspect the {@code cty} header to know how to handle the byte array without ambiguity.

* *

Note that the content and claims properties are mutually exclusive - only one of the two may be used.

@@ -163,14 +194,17 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setContent(byte[] content); + JwtBuilder content(byte[] content); /** * Convenience method that sets the JWT payload to be the specified content byte array and also sets the - * {@link Header#setContentType(String) contentType} header value to a compact {@code cty} media type + * {@link BuilderHeader#contentType(String) contentType} header value to a compact {@code cty} media type * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * + *

This method is mutually exclusive of the {@link #claim(String, Object)} and {@link #claims()} + * methods. Either {@code claims} or {@code content} method variants may be used, but not both.

+ * *

Compact Media Type Identifier

* *

As a convenience, this method will automatically trim any application/ prefix from the @@ -178,18 +212,18 @@ public interface JwtBuilder extends ClaimsMutator { * JWT specification recommendations.

* *

If for some reason you do not wish to adhere to the JWT specification recommendation, do not call this - * method - instead call {@link #setContent(byte[])} and set the header's - * {@link Header#setContentType(String) contentType} independently. For example:

+ * method - instead call {@link #content(byte[])} and set the header's + * {@link BuilderHeader#contentType(String) contentType} independently. For example:

* *
      * Jwts.builder()
-     *     .header().setContentType("application/whatever").and()
-     *     .setContent(byteArray)
+     *     .header().contentType("application/whatever").and()
+     *     .content(byteArray)
      *     ...
      *     .build();
* - *

If you want the JWT payload to be JSON claims, use the {@link #setClaims(Claims)} or - * {@link #setClaims(java.util.Map)} methods instead.

+ *

If you want the JWT payload to be JSON claims, use the {@link #claim(String, Object)} or + * {@link #claims()} methods instead.

* *

Note that the content and claims properties are mutually exclusive - only one of the two may be used.

* @@ -199,265 +233,209 @@ public interface JwtBuilder extends ClaimsMutator { * @throws IllegalArgumentException if either {@code payload} or {@code cty} are null or empty. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setContent(byte[] content, String cty) throws IllegalArgumentException; + JwtBuilder content(byte[] content, String cty) throws IllegalArgumentException; /** - * Sets the JWT payload to be a JSON Claims instance. If you do not want the JWT payload to be JSON claims and - * instead want it to be a byte array representing any type of content, use the {@link #setContent(byte[])} - * method instead. + * Returns the JWT {@code Claims} payload to modify as desired. When finished, callers may + * return to {@code JwtBuilder} configuration via the {@link BuilderClaims#and() and()} method. + * For example: + * + *
+     * String jwt = Jwts.builder()
      *
-     * 

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ * .claims() + * .subject("Joe") + * .audience("you") + * .issuer("me") + * .add("customClaim", customValue) + * .add(myClaimsMap) + * // ... etc ... + * .{@link BuilderClaims#and() and()} //return back to the JwtBuilder * - * @param claims the JWT claims to be set as the JWT payload. - * @return the builder for method chaining. + * .signWith(key) // resume JwtBuilder calls + * // ... etc ... + * .compact();
+ * + * @return the {@link BuilderClaims} to use for Claims construction. + * @since JJWT_RELEASE_VERSION */ - JwtBuilder setClaims(Claims claims); + BuilderClaims claims(); /** - * Sets the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. If you do not - * want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the - * {@link #setContent(byte[])} or {@link #setContent(byte[], String)} methods instead. + * Sets (and replaces) the JWT Claims payload with the specified name/value pairs. If you do not want the JWT + * payload to be JSON claims and instead want it to be a byte array for any content, use the + * {@link #content(byte[])} or {@link #content(byte[], String)} methods instead. * - *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ *

The content and claims properties are mutually exclusive - only one of the two may be used.

* * @param claims the JWT Claims to be set as the JWT payload. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #claims()} method. */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated JwtBuilder setClaims(Map claims); /** - * Adds all given name/value pairs to the JSON Claims in the payload. If a Claims instance does not yet exist at the - * time this method is called, one will be created automatically before applying the name/value pairs. + * Adds/appends all given name/value pairs to the JSON Claims in the payload. + *

+ * This is a convenience wrapper for: * - *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ *
+     * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()}
+ * + *

The content and claims properties are mutually exclusive - only one of the two may be used.

* * @param claims the JWT Claims to be added to the JWT payload. * @return the builder for method chaining. * @since 0.8 + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #claims()}.{@link BuilderClaims#add(Map) add(Map)}.{@link BuilderClaims#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated JwtBuilder addClaims(Map claims); /** - * Sets the JWT Claims - * iss (issuer) value. A {@code null} value will remove the property from the Claims. + * Sets a JWT claim, overwriting any existing claim with the same name. A {@code null} or empty + * value will remove the claim entirely. This is a convenience wrapper for: + *
+     * {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderClaims#and() and()}
* - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getIssuer() issuer} field with the specified value. This allows you to write - * code like this:

+ * @param name the JWT Claims property name + * @param value the value to set for the specified Claims property name + * @return the builder instance for method chaining. + * @since 0.2 + */ + JwtBuilder claim(String name, Object value); + + /** + * Adds all given name/value pairs to the JSON Claims in the payload, overwriting any existing claims + * with the same names. If any name has a {@code null} or empty value, that claim will be removed from the + * Claims. This is a convenience wrapper for: + *
+     * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()}
* - *
-     * String jwt = Jwts.builder().setIssuer("Joe").compact();
-     * 
+ *

The content and claims properties are mutually exclusive - only one of the two may be used.

* - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setIssuer("Joe").build();
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ * @param claims the JWT Claims to be added to the JWT payload. + * @return the builder instance for method chaining + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder claims(Map claims); + + /** + * Sets the JWT Claims + * iss (issuer) value. A {@code null} value will remove the property from the Claims. + * This is a convenience wrapper for: + *
+     * {@link #claims()}.{@link ClaimsMutator#issuer(String) issuer(iss)}.{@link BuilderClaims#and() and()}
* * @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setIssuer(String iss); + // for better/targeted JavaDoc + JwtBuilder issuer(String iss); /** - * Sets the JWT Claims + * Sets the JWT Claims * sub (subject) value. A {@code null} value will remove the property from the Claims. - * - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getSubject() subject} field with the specified value. This allows you to write - * code like this:

- * - *
-     * String jwt = Jwts.builder().setSubject("Me").compact();
- * - *

instead of this:

+ * This is a convenience wrapper for: *
-     * Claims claims = Jwts.claims().setSubject("Me").build();
-     * String jwt = Jwts.builder().setClaims(claims).compact();
- *

if desired.

+ * {@link #claims()}.{@link ClaimsMutator#subject(String) subject(sub)}.{@link BuilderClaims#and() and()} * * @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setSubject(String sub); + // for better/targeted JavaDoc + JwtBuilder subject(String sub); /** - * Sets the JWT Claims + * Sets the JWT Claims * aud (audience) value. A {@code null} value will remove the property from the Claims. - * - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getAudience() audience} field with the specified value. This allows you to write - * code like this:

- * - *
-     * String jwt = Jwts.builder().setAudience("You").compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setAudience("You");
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ * This is a convenience wrapper for: + *
+     * {@link #claims()}.{@link ClaimsMutator#audience(String) audience(aud)}.{@link BuilderClaims#and() and()}
* * @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setAudience(String aud); + // for better/targeted JavaDoc + JwtBuilder audience(String aud); /** - * Sets the JWT Claims + * Sets the JWT Claims * exp (expiration) value. A {@code null} value will remove the property from the Claims. * *

A JWT obtained after this timestamp should not be used.

* - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getExpiration() expiration} field with the specified value. This allows - * you to write code like this:

- * - *
-     * String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ *

This is a convenience wrapper for:

+ *
+     * {@link #claims()}.{@link ClaimsMutator#expiration(Date) expiration(exp)}.{@link BuilderClaims#and() and()}
* * @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setExpiration(Date exp); + // for better/targeted JavaDoc + JwtBuilder expiration(Date exp); /** - * Sets the JWT Claims + * Sets the JWT Claims * nbf (not before) value. A {@code null} value will remove the property from the Claims. * *

A JWT obtained before this timestamp should not be used.

* - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getNotBefore() notBefore} field with the specified value. This allows - * you to write code like this:

- * - *
-     * String jwt = Jwts.builder().setNotBefore(new Date()).compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setNotBefore(new Date());
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ *

This is a convenience wrapper for:

+ *
+     * {@link #claims()}.{@link ClaimsMutator#notBefore(Date) notBefore(nbf)}.{@link BuilderClaims#and() and()}
* * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc + // for better/targeted JavaDoc JwtBuilder setNotBefore(Date nbf); /** - * Sets the JWT Claims + * Sets the JWT Claims * iat (issued at) value. A {@code null} value will remove the property from the Claims. * *

The value is the timestamp when the JWT was created.

* - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getIssuedAt() issuedAt} field with the specified value. This allows - * you to write code like this:

- * - *
-     * String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setIssuedAt(new Date());
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ *

This is a convenience wrapper for:

+ *
+     * {@link #claims()}.{@link ClaimsMutator#issuedAt(Date) issuedAt(iat)}.{@link BuilderClaims#and() and()}
* * @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setIssuedAt(Date iat); + // for better/targeted JavaDoc + JwtBuilder issuedAt(Date iat); /** - * Sets the JWT Claims + * Sets the JWT Claims * jti (JWT ID) value. A {@code null} value will remove the property from the Claims. * *

The value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a * manner that ensures that there is a negligible probability that the same value will be accidentally * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

* - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getId() id} field with the specified value. This allows - * you to write code like this:

- * - *
-     * String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().setId(UUID.randomUUID().toString());
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

+ *

This is a convenience wrapper for:

+ *
+     * {@link #claims()}.{@link ClaimsMutator#id(String) id(jti)}.{@link BuilderClaims#and() and()}
* * @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ @Override - //only for better/targeted JavaDoc - JwtBuilder setId(String jti); - - /** - * Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims. - * - *

This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set the - * named property on the Claims instance using the Claims {@link Claims#put(Object, Object) put} method. This allows - * you to write code like this:

- * - *
-     * String jwt = Jwts.builder().claim("aName", "aValue").compact();
-     * 
- * - *

instead of this:

- *
-     * Claims claims = Jwts.claims().put("aName", "aValue");
-     * String jwt = Jwts.builder().setClaims(claims).compact();
-     * 
- *

if desired.

- * - * @param name the JWT Claims property name - * @param value the value to set for the specified Claims property name - * @return the builder instance for method chaining. - * @since 0.2 - */ - JwtBuilder claim(String name, Object value); + // for better/targeted JavaDoc + JwtBuilder id(String jti); /** * Signs the constructed JWT with the specified key using the key's recommended signature algorithm @@ -760,7 +738,7 @@ public interface JwtBuilder extends ClaimsMutator { * {@code enc} algorithm. In this case, the {@code key} argument MUST be of sufficient strength to * use with the specified {@code enc} algorithm, otherwise an exception will be thrown during encryption. If * desired, secure-random keys suitable for an {@link AeadAlgorithm} may be generated using the algorithm's - * {@link AeadAlgorithm#keyBuilder() keyBuilder}. + * {@link AeadAlgorithm#key() key()} builder. * * * @param key the symmetric encryption key to use with the {@code enc} algorithm. @@ -828,19 +806,35 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder compressWith(CompressionAlgorithm alg); /** - * Perform Base64Url encoding with the specified Encoder. + * Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder. * *

JJWT uses a spec-compliant encoder that works on all supported JDK versions, but you may call this method * to specify a different encoder if you desire.

* * @param base64UrlEncoder the encoder to use when Base64Url-encoding * @return the builder for method chaining. + * @see #encoder(Encoder) * @since 0.10.0 + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style + * {@link #encoder(Encoder)} method. */ + @Deprecated JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder); /** - * Performs object-to-JSON serialization with the specified Serializer. This is used by the builder to convert + * Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder. + * + *

JJWT uses a spec-compliant encoder that works on all supported JDK versions, but you may call this method + * to specify a different encoder if necessar.

+ * + * @param encoder the encoder to use when Base64Url-encoding + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder encoder(Encoder encoder); + + /** + * Performs Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert * JWT/JWS/JWE headers and claims Maps to JSON strings as required by the JWT specification. * *

If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the @@ -850,12 +844,29 @@ public interface JwtBuilder extends ClaimsMutator { * @param serializer the serializer to use when converting Map objects to JSON strings. * @return the builder for method chaining. * @since 0.10.0 + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style + * {@link #serializer(Serializer)} method. */ + @Deprecated JwtBuilder serializeToJsonWith(Serializer> serializer); + /** + * Perform Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert + * JWT/JWS/JWE headers and Claims Maps to JSON strings as required by the JWT specification. + * + *

If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the + * presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found + * in the runtime classpath, an exception will be thrown when the {@link #compact()} method is invoked.

+ * + * @param serializer the serializer to use when converting Map objects to JSON strings. + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder serializer(Serializer> serializer); + /** * Actually builds the JWT and serializes it to a compact, URL-safe string according to the - * JWT Compact Serialization + * JWT Compact Serialization * rules. * * @return A compact URL-safe JWT string. @@ -863,13 +874,30 @@ public interface JwtBuilder extends ClaimsMutator { String compact(); /** - * Editable header for use with a {@link JwtBuilder} that supports method chaining for any/all + * Claims for use with a {@link JwtBuilder} that supports method chaining for standard JWT Claims parameters. + * Once claims are configured, the associated {@link JwtBuilder} may be obtained with the {@link #and() and()} + * method for continued configuration. + * + * @since JJWT_RELEASE_VERSION + */ + interface BuilderClaims extends MapMutator, ClaimsMutator { + + /** + * Returns the associated JwtBuilder for continued configuration. + * + * @return the associated JwtBuilder for continued configuration. + */ + JwtBuilder and(); + } + + /** + * Header for use with a {@link JwtBuilder} that supports method chaining for * standard JWT, JWS and JWE header parameters. Once header parameters are configured, the associated * {@link JwtBuilder} may be obtained with the {@link #and() and()} method for continued configuration. * * @since JJWT_RELEASE_VERSION */ - interface Header extends JweHeaderMutator
, X509Builder
{ + interface BuilderHeader extends JweHeaderMutator, X509Builder { /** * Returns the associated JwtBuilder for continued configuration. diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index eadf800ea..2d0f7238c 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -23,8 +23,11 @@ import io.jsonwebtoken.security.KeyAlgorithm; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import javax.crypto.SecretKey; import java.security.Key; +import java.security.PrivateKey; import java.security.Provider; +import java.security.PublicKey; import java.util.Collection; import java.util.Date; import java.util.Map; @@ -45,11 +48,11 @@ public interface JwtParserBuilder extends Builder { /** - * Enables parsing of Unsecured JWSs (JWTs with an 'alg' (Algorithm) header value of - * 'none'). Be careful when calling this method - one should fully understand + * Enables parsing of Unsecured JWTs (JWTs with an 'alg' (Algorithm) header value of + * 'none' or missing the 'alg' header entirely). Be careful when calling this method - one should fully understand * Unsecured JWS Security Considerations * before enabling this feature. - *

If this method is not called, Unsecured JWSs are disabled by default as mandated by + *

If this method is not called, Unsecured JWTs are disabled by default as mandated by * RFC 7518, Section * 3.6.

* @@ -60,23 +63,23 @@ public interface JwtParserBuilder extends Builder { * @see #enableUnsecuredDecompression() * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder enableUnsecuredJws(); + JwtParserBuilder enableUnsecured(); /** - * If {@link #enableUnsecuredJws() enabledUnsecuredJws} is enabled, calling this method additionally enables - * payload decompression of Unsecured JWSs (JWTs with an 'alg' (Algorithm) header value of 'none') that also have + * If {@link #enableUnsecured() enabledUnsecuredJws} is enabled, calling this method additionally enables + * payload decompression of Unsecured JWTs (JWTs with an 'alg' (Algorithm) header value of 'none') that also have * a 'zip' (Compression) header. This behavior is disabled by default because using compression * algorithms with data from unverified (unauthenticated) parties can be susceptible to Denial of Service attacks * and other data integrity problems as described in * In the * Compression Hornet’s Nest: A Security Study of Data Compression in Network Services. * - *

Because this behavior is only relevant if {@link #enableUnsecuredJws() enabledUnsecuredJws} is specified, - * calling this method without also calling {@code enableUnsecuredJws()} will result in a build exception, as the + *

Because this behavior is only relevant if {@link #enableUnsecured() enabledUnsecured} is specified, + * calling this method without also calling {@code enableUnsecured()} will result in a build exception, as the * incongruent state could reflect a misunderstanding of both behaviors which should be remedied by the * application developer.

* - * As is the case for {@link #enableUnsecuredJws()}, be careful when calling this method - one should fully + * As is the case for {@link #enableUnsecured()}, be careful when calling this method - one should fully * understand * Unsecured JWS Security Considerations * before enabling this feature. @@ -86,7 +89,7 @@ public interface JwtParserBuilder extends Builder { * @see In the * Compression Hornet’s Nest: A Security Study of Data Compression in Network Services * @see Jwts.SIG#NONE - * @see #enableUnsecuredJws() + * @see #enableUnsecured() * @since JJWT_RELEASE_VERSION */ JwtParserBuilder enableUnsecuredDecompression(); @@ -100,7 +103,7 @@ public interface JwtParserBuilder extends Builder { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder setProvider(Provider provider); + JwtParserBuilder provider(Provider provider); /** * Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed @@ -205,9 +208,21 @@ public interface JwtParserBuilder extends Builder { * * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT. * @return the parser builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION for the more modern builder-style named {@link #clock(Clock)} method. + * This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder setClock(Clock clock); + /** + * Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT. + * The parser uses a default Clock implementation that simply returns {@code new Date()} when called. + * + * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT. + * @return the parser builder for method chaining. + */ + JwtParserBuilder clock(Clock clock); + /** * Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp} * and {@code nbf} claims. @@ -217,16 +232,31 @@ public interface JwtParserBuilder extends Builder { * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as * any such value would cause numeric overflow when multiplying by 1000 to obtain * a millisecond value. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #clockSkewSeconds(long)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException; + /** + * Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp} + * and {@code nbf} claims. + * + * @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims. + * @return the parser builder for method chaining. + * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as + * any such value would cause numeric overflow when multiplying by 1000 to obtain + * a millisecond value. + */ + JwtParserBuilder clockSkewSeconds(long seconds) throws IllegalArgumentException; + /** *

Deprecation Notice

* *

This method has been deprecated since JJWT_RELEASE_VERSION and will be removed before 1.0. It was not * readily obvious to many JJWT users that this method was for bytes that pertained only to HMAC * {@code SecretKey}s, and could be confused with keys of other types. It is better to obtain a type-safe - * {@link Key} instance and call the {@link #verifyWith(Key)} instead.

+ * {@link SecretKey} instance and call {@link #verifyWith(SecretKey)} instead.

* *

Previous Documentation

* @@ -241,8 +271,8 @@ public interface JwtParserBuilder extends Builder { * @param key the algorithm-specific signature verification key used to validate any discovered JWS digital * signature. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(Key)} for type safety and name congruence - * with the {@link #decryptWith(Key)} method. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(SecretKey)} for type safety and name + * congruence with the {@link #decryptWith(SecretKey)} method. */ @Deprecated JwtParserBuilder setSigningKey(byte[] key); @@ -268,7 +298,7 @@ public interface JwtParserBuilder extends Builder { * StackOverflow answer explaining why raw (non-base64-encoded) strings are almost always incorrect for * signature operations.

* - *

Finally, please use the {@link #verifyWith(Key)} method instead, as this method (and likely + *

Finally, please use the {@link #verifyWith(SecretKey)} method instead, as this method (and likely * {@link #setSigningKey(byte[])}) will be removed before the 1.0.0 release.

* *

Previous JavaDoc

@@ -278,12 +308,12 @@ public interface JwtParserBuilder extends Builder { *
      * byte[] bytes = Decoders.{@link io.jsonwebtoken.io.Decoders#BASE64 BASE64}.decode(base64EncodedSecretKey);
      * Key key = Keys.{@link io.jsonwebtoken.security.Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor}(bytes);
-     * return {@link #verifyWith(Key) verifyWith}(key);
+ * return {@link #verifyWith(SecretKey) verifyWith}(key); * * @param base64EncodedSecretKey BASE64-encoded HMAC-SHA key bytes used to create a Key which will be used to * verify all encountered JWS digital signatures. * @return the parser builder for method chaining. - * @deprecated in favor of {@link #verifyWith(Key)} as explained in the above Deprecation Notice, + * @deprecated in favor of {@link #verifyWith(SecretKey)} as explained in the above Deprecation Notice, * and will be removed in 1.0.0. */ @Deprecated @@ -295,63 +325,104 @@ public interface JwtParserBuilder extends Builder { *

This method is being renamed to accurately reflect its purpose - the key is not technically a signing key, * it is a signature verification key, and the two concepts can be different, especially with asymmetric key * cryptography. The method has been deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #verifyWith(Key)} for type safety, to reflect accurate naming of the concept, and for name congruence - * with the {@link #decryptWith(Key)} method.

+ * {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name + * congruence with the {@link #decryptWith(SecretKey)} method.

* - *

This method merely delegates directly to {@link #verifyWith(Key)}.

+ *

This method merely delegates directly to {@link #verifyWith(SecretKey)}.

* * @param key the algorithm-specific signature verification key to use to verify all encountered JWS digital * signatures. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(Key)} for naming congruence with the - * {@link #decryptWith(Key)} method. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(SecretKey)} for naming congruence with the + * {@link #decryptWith(SecretKey)} method. */ @Deprecated JwtParserBuilder setSigningKey(Key key); /** - * Sets the signature verification key used to verify all encountered JWS signatures. If the encountered JWT + * Sets the signature verification SecretKey used to verify all encountered JWS signatures. If the encountered JWT + * string is not a JWS (e.g. unsigned or a JWE), this key is not used. + * + *

This is a convenience method to use in a specific scenario: when the parser will only ever encounter + * JWSs with signatures that can always be verified by a single SecretKey. This also implies that this key + * MUST be a valid key for the signature algorithm ({@code alg} header) used for the JWS.

+ * + *

If there is any chance that the parser will also encounter JWEs, or JWSs that need different signature + * verification keys based on the JWS being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

+ * + *

Calling this method overrides any previously set signature verification key.

+ * + * @param key the signature verification key to use to verify all encountered JWS digital signatures. + * @return the parser builder for method chaining. + * @see #verifyWith(PublicKey) + * @since JJWT_RELEASE_VERSION + */ + JwtParserBuilder verifyWith(SecretKey key); + + /** + * Sets the signature verification PublicKey used to verify all encountered JWS signatures. If the encountered JWT * string is not a JWS (e.g. unsigned or a JWE), this key is not used. * *

This is a convenience method to use in a specific scenario: when the parser will only ever encounter - * JWSs with signatures that can always be verified by a single key. This also implies that this key + * JWSs with signatures that can always be verified by a single PublicKey. This also implies that this key * MUST be a valid key for the signature algorithm ({@code alg} header) used for the JWS.

* - *

If there is any chance that the parser will encounter JWSs - * that need different signature verification keys based on the JWS being parsed, or JWEs, it is strongly - * recommended to configure your own {@link Locator} via the - * {@link #setKeyLocator(Locator) setKeyLocator} method instead of using this one.

+ *

If there is any chance that the parser will also encounter JWEs, or JWSs that need different signature + * verification keys based on the JWS being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

* *

Calling this method overrides any previously set signature verification key.

* * @param key the signature verification key to use to verify all encountered JWS digital signatures. * @return the parser builder for method chaining. + * @see #verifyWith(SecretKey) * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder verifyWith(Key key); + JwtParserBuilder verifyWith(PublicKey key); /** - * Sets the decryption key used to decrypt all encountered JWEs, overwriting any previously configured - * {@link #setKeyLocator(Locator) keyLocator}. If the encountered JWT string is not a JWE (e.g. a JWS), - * this key is not used. + * Sets the decryption SecretKey used to decrypt all encountered JWEs. If the encountered JWT string is not a + * JWE (e.g. a JWS), this key is not used. * *

This is a convenience method to use in specific circumstances: when the parser will only ever encounter - * JWEs that can always be decrypted by a single key. This also implies that this key MUST be a valid + * JWEs that can always be decrypted by a single SecretKey. This also implies that this key MUST be a valid * key for both the key management algorithm ({@code alg} header) and the content encryption algorithm * ({@code enc} header) used for the JWE.

* - *

If there is any chance that the parser will encounter JWEs that need different decryption keys based on the - * JWE being parsed, or JWSs, it is strongly recommended to configure - * your own {@link Locator Locator} via the {@link #setKeyLocator(Locator) setKeyLocator} method instead of - * using {@code decryptWith}.

+ *

If there is any chance that the parser will also encounter JWSs, or JWEs that need different decryption + * keys based on the JWE being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

* *

Calling this method overrides any previously set decryption key.

* * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. * @return the parser builder for method chaining. + * @see #decryptWith(PrivateKey) * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder decryptWith(Key key); + JwtParserBuilder decryptWith(SecretKey key); + + /** + * Sets the decryption PrivateKey used to decrypt all encountered JWEs. If the encountered JWT string is not a + * JWE (e.g. a JWS), this key is not used. + * + *

This is a convenience method to use in specific circumstances: when the parser will only ever encounter JWEs + * that can always be decrypted by a single PrivateKey. This also implies that this key MUST be a valid + * key for the JWE's key management algorithm ({@code alg} header).

+ * + *

If there is any chance that the parser will also encounter JWSs, or JWEs that need different decryption + * keys based on the JWE being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

+ * + *

Calling this method overrides any previously set decryption key.

+ * + * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. + * @return the parser builder for method chaining. + * @see #decryptWith(SecretKey) + * @since JJWT_RELEASE_VERSION + */ + JwtParserBuilder decryptWith(PrivateKey key); /** * Sets the {@link Locator} used to acquire any signature verification or decryption key needed during parsing. @@ -361,13 +432,13 @@ public interface JwtParserBuilder extends Builder { *
  • If the parsed String is a JWE, it will be called to find the appropriate decryption key.
  • * * - *

    Specifying a key {@code Locator} is necessary when the signing or decryption key is not already known before - * parsing the JWT and the JWT header must be inspected first to determine how to + *

    Specifying a key {@code Locator} is necessary when the signature verification or decryption key is not + * already known before parsing the JWT and the JWT header must be inspected first to determine how to * look up the verification or decryption key. Once returned by the locator, the JwtParser will then either * verify the JWS signature or decrypt the JWE payload with the returned key. For example:

    * *
    -     * Jws<Claims> jws = Jwts.parser().setKeyLocator(new Locator<Key>() {
    +     * Jws<Claims> jws = Jwts.parser().keyLocator(new Locator<Key>() {
          *         @Override
          *         public Key locate(Header<?> header) {
          *             if (header instanceof JwsHeader) {
    @@ -386,14 +457,14 @@ public interface JwtParserBuilder extends Builder {
          * @return the parser builder for method chaining.
          * @since JJWT_RELEASE_VERSION
          */
    -    JwtParserBuilder setKeyLocator(Locator keyLocator);
    +    JwtParserBuilder keyLocator(Locator keyLocator);
     
         /**
          * 

    Deprecation Notice

    * *

    This method has been deprecated as of JJWT version JJWT_RELEASE_VERSION because it only supports key location * for JWSs (signed JWTs) instead of both signed (JWS) and encrypted (JWE) scenarios. Use the - * {@link #setKeyLocator(Locator) setKeyLocator} method instead to ensure a locator that can work for both JWS and + * {@link #keyLocator(Locator) keyLocator} method instead to ensure a locator that can work for both JWS and * JWE inputs. This method will be removed for the 1.0 release.

    * *

    Previous Documentation

    @@ -420,7 +491,7 @@ public interface JwtParserBuilder extends Builder { * * @param signingKeyResolver the signing key resolver used to retrieve the signing key. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #setKeyLocator(Locator)} + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #keyLocator(Locator)} */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -428,82 +499,109 @@ public interface JwtParserBuilder extends Builder { /** * Adds the specified compression algorithms to the parser's total set of supported compression algorithms, - * overwriting any previously-added compression algorithms with the same {@link CompressionAlgorithm#getId() id}s. - * If the parser encounters a JWT {@code zip} header value that matches a compression algorithm's - * {@link CompressionAlgorithm#getId() id}, that algorithm will be used for decompression. + * replacing any existing ones with identical {@link Identifiable#getId() id}s. + * If the parser encounters a JWT {@code zip} header value that equals a compression algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for decompression. * - *

    There may be only one registered {@code CompressionAlgorithm} per {@code id}, and the {@code algs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

    + *

    There may be only one registered {@code CompressionAlgorithm} per CaSe-SeNsItIvE {@code id}, and the + * {@code algs} collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * collection, the later algorithm will evict any existing algorithm with the same {@code id}.

    + * + *

    Standard Algorithms and Overrides

    * - *

    Finally, {@link Jwts.ZIP#DEF} and {@link Jwts.ZIP#GZIP} algorithms are added last, - * after those in the {@code algs} collection, to ensure that JWA standard algorithms cannot be - * accidentally replaced.

    + *

    The {@link Jwts.ZIP} compression algorithms are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param algs collection of compression algorithms to add to the parser's total set of supported compression algorithms. + * @param algs collection of compression algorithms to add to the parser's total set of supported compression + * algorithms, replacing any existing ones with the same exact (CaSe-SeNsItIvE) + * {@link CompressionAlgorithm#getId() id}s. * @return the builder for method chaining. + * @see Jwts.ZIP * @since JJWT_RELEASE_VERSION */ JwtParserBuilder addCompressionAlgorithms(Collection algs); /** * Adds the specified AEAD encryption algorithms to the parser's total set of supported encryption algorithms, - * overwriting any previously-added algorithms with the same {@link AeadAlgorithm#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link AeadAlgorithm#getId() id}s. + * If the parser encounters a JWT {@code enc} header value that equals an encryption algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for decryption. + * + *

    There may be only one registered {@code AeadAlgorithm} per algorithm {@code id}, and the {@code algs} + * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * collection, the later algorithm will evict any existing algorithm with the same {@code id}.

    * - *

    There may be only one registered {@code AeadAlgorithm} per algorithm {@code id}, and the {@code encAlgs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code encAlgs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

    + *

    Standard Algorithms and Overrides

    * - *

    Finally, the {@link Jwts.ENC JWA standard encryption algorithms} are added last, - * after those in the {@code encAlgs} collection, to ensure that JWA standard algorithms cannot be - * accidentally replaced.

    + *

    All JWA standard encryption algorithms in {@link Jwts.ENC} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param encAlgs collection of AEAD encryption algorithms to add to the parser's total set of supported - * encryption algorithms. + * @param algs collection of AEAD encryption algorithms to add to the parser's total set of supported + * encryption algorithms, replacing any existing algorithms with the same + * {@link AeadAlgorithm#getId() id}s. * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addEncryptionAlgorithms(Collection encAlgs); + JwtParserBuilder addEncryptionAlgorithms(Collection algs); /** * Adds the specified signature algorithms to the parser's total set of supported signature algorithms, - * overwriting any previously-added algorithms with the same - * {@link Identifiable#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link Identifiable#getId() id}s. + * If the parser encounters a JWS {@code alg} header value that equals a signature algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for signature verification. * *

    There may be only one registered {@code SecureDigestAlgorithm} per algorithm {@code id}, and the - * {@code sigAlgs} collection is added in iteration order; if a duplicate id is found when iterating the - * {@code sigAlgs} collection, the later element will evict any previously-added algorithm with the same - * {@code id}.

    + * {@code algs} collection is added in iteration order; if a duplicate id is found when iterating the + * {@code algs} argument, the later algorithm will evict any existing algorithm with the same {@code id}.

    * - *

    Finally, the {@link Jwts.SIG JWA standard signature and MAC algorithms} are - * added last, after those in the {@code sigAlgs} collection, to ensure that JWA standard algorithms - * cannot be accidentally replaced.

    + *

    Standard Algorithms and Overrides

    * - * @param sigAlgs collection of signing algorithms to add to the parser's total set of supported signature - * algorithms. + *

    All JWA standard signature and MAC algorithms in {@link Jwts.SIG} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard + * algorithm implementation. This is to allow application developers to favor their own implementations over + * JJWT's default implementations if necessary (for example, to support legacy or custom behavior). + * + * @param algs collection of signature algorithms to add to the parser's total set of supported signature + * algorithms, replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) + * {@link Identifiable#getId() id}s. * @return the builder for method chaining. + * @see Algorithm Name (id) requirements * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addSignatureAlgorithms(Collection> sigAlgs); + JwtParserBuilder addSignatureAlgorithms(Collection> algs); /** * Adds the specified key management algorithms to the parser's total set of supported key algorithms, - * overwriting any previously-added algorithms with the same {@link KeyAlgorithm#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link KeyAlgorithm#getId() id}s. + * If the parser encounters a JWE {@code alg} header value that equals a key management algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used to obtain the content decryption key. + * + *

    There may be only one registered {@code KeyAlgorithm} per algorithm {@code id}, and the {@code algs} + * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * argument, the later algorithm will evict any existing algorithm with the same {@code id}.

    * - *

    There may be only one registered {@code KeyAlgorithm} per algorithm {@code id}, and the {@code keyAlgs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code keyAlgs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

    + *

    Standard Algorithms and Overrides

    * - *

    Finally, the {@link Jwts.KEY#get() JWA standard key management algorithms} - * are added last, after those in the {@code keyAlgs} collection, to ensure that JWA standard algorithms - * cannot be accidentally replaced.

    + *

    All JWA standard key management algorithms in {@link Jwts.KEY} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param keyAlgs collection of key management algorithms to add to the parser's total set of supported key - * management algorithms. + * @param algs collection of key management algorithms to add to the parser's total set of supported key + * management algorithms, replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) + * {@link KeyAlgorithm#getId() id}s. * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addKeyAlgorithms(Collection> keyAlgs); + JwtParserBuilder addKeyAlgorithms(Collection> algs); /** *

    Deprecated as of JJWT JJWT_RELEASE_VERSION. This method will be removed before the 1.0 release.

    @@ -531,6 +629,7 @@ public interface JwtParserBuilder extends Builder { * @param compressionCodecResolver the compression codec resolver used to decompress the JWT body. * @return the parser builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #addCompressionAlgorithms(Collection)}. + * This method will be removed before the 1.0 release. */ @Deprecated JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver); @@ -543,9 +642,23 @@ public interface JwtParserBuilder extends Builder { * * @param base64UrlDecoder the decoder to use when Base64Url-decoding * @return the parser builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #decoder(Decoder)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder); + /** + * Perform Base64Url decoding with the specified Decoder + * + *

    JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method + * to specify a different decoder if you desire.

    + * + * @param base64UrlDecoder the decoder to use when Base64Url-decoding + * @return the parser builder for method chaining. + */ + JwtParserBuilder decoder(Decoder base64UrlDecoder); + /** * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is * used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map @@ -558,9 +671,27 @@ public interface JwtParserBuilder extends Builder { * * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #deserializer(Deserializer)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder deserializeJsonWith(Deserializer> deserializer); + /** + * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is + * used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map + * objects. + * + *

    If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the + * presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found + * in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is + * invoked.

    + * + * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects. + * @return the builder for method chaining. + */ + JwtParserBuilder deserializer(Deserializer> deserializer); + /** * Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder. * diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java index 8c1ca43ac..26ae06714 100644 --- a/api/src/main/java/io/jsonwebtoken/Jwts.java +++ b/api/src/main/java/io/jsonwebtoken/Jwts.java @@ -365,7 +365,7 @@ public static final class KEY { *

    During JWE creation, this algorithm:

    *
      *
    1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
    2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
    3. Encrypts this newly-generated {@code SecretKey} with a 128-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
    4. *
    5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -389,7 +389,7 @@ public static final class KEY { *

      During JWE creation, this algorithm:

      *
        *
      1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
      2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
      3. Encrypts this newly-generated {@code SecretKey} with a 192-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
      4. *
      5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -413,7 +413,7 @@ public static final class KEY { *

        During JWE creation, this algorithm:

        *
          *
        1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
        2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
        3. Encrypts this newly-generated {@code SecretKey} with a 256-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
        4. *
        5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -437,7 +437,7 @@ public static final class KEY { *

          During JWE creation, this algorithm:

          *
            *
          1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
          2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
          3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
          4. *
          5. Encrypts this newly-generated {@code SecretKey} with a 128-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -476,7 +476,7 @@ public static final class KEY { *

            During JWE creation, this algorithm:

            *
              *
            1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
            2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
            3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
            4. *
            5. Encrypts this newly-generated {@code SecretKey} with a 192-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -515,7 +515,7 @@ public static final class KEY { *

              During JWE creation, this algorithm:

              *
                *
              1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
              4. *
              5. Encrypts this newly-generated {@code SecretKey} with a 256-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -564,7 +564,7 @@ public static final class KEY { *
              6. Derives a 128-bit Key Encryption Key with the PBES2-HS256 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              7. *
              8. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              9. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              10. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A128KW} key wrap * algorithm using the 128-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              11. @@ -609,7 +609,7 @@ public static final class KEY { *
              12. Derives a 192-bit Key Encryption Key with the PBES2-HS384 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              13. *
              14. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              15. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              16. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A192KW} key wrap * algorithm using the 192-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              17. @@ -654,7 +654,7 @@ public static final class KEY { *
              18. Derives a 256-bit Key Encryption Key with the PBES2-HS512 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              19. *
              20. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              21. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              22. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A256KW} key wrap * algorithm using the 256-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              23. @@ -690,7 +690,7 @@ public static final class KEY { *

                During JWE creation, this algorithm:

                *
                  *
                1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                3. Encrypts this newly-generated {@code SecretKey} with the RSA key wrap algorithm, using the JWE * recipient's RSA Public Key, producing encrypted key ciphertext.
                4. *
                5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -715,7 +715,7 @@ public static final class KEY { *

                  During JWE creation, this algorithm:

                  *
                    *
                  1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                  2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                  3. Encrypts this newly-generated {@code SecretKey} with the RSA OAEP with SHA-1 and MGF1 key wrap algorithm, * using the JWE recipient's RSA Public Key, producing encrypted key ciphertext.
                  4. *
                  5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -740,7 +740,7 @@ public static final class KEY { *

                    During JWE creation, this algorithm:

                    *
                      *
                    1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    3. Encrypts this newly-generated {@code SecretKey} with the RSA OAEP with SHA-256 and MGF1 key wrap * algorithm, using the JWE recipient's RSA Public Key, producing encrypted key ciphertext.
                    4. *
                    5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -818,7 +818,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE.
                    6. *
                    7. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    8. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    9. Encrypts this newly-generated {@code SecretKey} with the {@code A128KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key ciphertext.
                    10. *
                    11. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -866,7 +866,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE.
                    12. *
                    13. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    14. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    15. Encrypts this newly-generated {@code SecretKey} with the {@code A192KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key * ciphertext.
                    16. @@ -915,7 +915,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE. *
                    17. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    18. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    19. Encrypts this newly-generated {@code SecretKey} with the {@code A256KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key * ciphertext.
                    20. @@ -1041,7 +1041,7 @@ public static ClaimsBuilder claims() { /** *

                      Deprecated since JJWT_RELEASE_VERSION in favor of - * {@code Jwts.}{@link #claims()}{@code .set(map).build()}. + * {@code Jwts.}{@link #claims()}{@code .add(map).build()}. * This method will be removed before 1.0.

                      * *

                      Returns a new {@link Claims} instance populated with the specified name/value pairs.

                      @@ -1053,16 +1053,7 @@ public static ClaimsBuilder claims() { */ @Deprecated public static Claims claims(Map claims) { - return claims().set(claims).build(); - } - - /** - * Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser}. - * - * @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser}. - */ - public static JwtParserBuilder parser() { - return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder"); + return claims().add(claims).build(); } /** @@ -1076,6 +1067,15 @@ public static JwtBuilder builder() { return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder"); } + /** + * Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser}. + * + * @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser}. + */ + public static JwtParserBuilder parser() { + return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder"); + } + /** * Private constructor, prevent instantiation. */ diff --git a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java index 3c4a8ef9b..5c329a345 100644 --- a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java @@ -30,20 +30,17 @@ public interface ProtectedHeaderMutator> extends HeaderMutator, X509Mutator { /** - * Sets the {@code jku} (JWK Set URL) value that refers to a - * JWK Set - * resource containing JSON-encoded Public Keys, or {@code null} if not present. When set for a - * {@link JwsHeader}, the first public key in the JWK Set must be the public key complement of the - * private key used to sign the JWS. When set for a {@link JweHeader}, the first public key in the JWK Set - * must be the public key used during encryption. + * Sets the header parameter names that use extensions to the JWT or JWA specification that MUST + * be understood and supported by the JWT recipient. A {@code null} value will remove the + * property from the JSON map. * - * @param uri a URI that refers to a JWK Set - * resource containing JSON-encoded Public Keys - * @return the header for method chaining - * @see JWS JWK Set URL - * @see JWE JWK Set URL + * @param crit the header parameter names that use extensions to the JWT or JWA specification that MUST + * be understood and supported by the JWT recipient. + * @return the header for method chaining. + * @see JWS crit (Critical) Header Parameter + * @see JWS crit (Critical) Header Parameter */ - T setJwkSetUrl(URI uri); + T critical(Set crit); /** * Sets the {@code jwk} (JSON Web Key) associated with the JWT. When set for a {@link JwsHeader}, the @@ -56,7 +53,23 @@ public interface ProtectedHeaderMutator> ext * @see JWS jwk (JSON Web Key) Header Parameter * @see JWE jwk (JSON Web Key) Header Parameter */ - T setJwk(PublicJwk jwk); + T jwk(PublicJwk jwk); + + /** + * Sets the {@code jku} (JWK Set URL) value that refers to a + * JWK Set + * resource containing JSON-encoded Public Keys, or {@code null} if not present. When set for a + * {@link JwsHeader}, the first public key in the JWK Set must be the public key complement of the + * private key used to sign the JWS. When set for a {@link JweHeader}, the first public key in the JWK Set + * must be the public key used during encryption. + * + * @param uri a URI that refers to a JWK Set + * resource containing JSON-encoded Public Keys + * @return the header for method chaining + * @see JWS JWK Set URL + * @see JWE JWK Set URL + */ + T jwkSetUrl(URI uri); /** * Sets the JWT case-sensitive {@code kid} (Key ID) header value. A {@code null} value will remove the property @@ -73,18 +86,29 @@ public interface ProtectedHeaderMutator> ext * @see JWS Key ID * @see JWE Key ID */ + T keyId(String kid); + + /** + * Deprecated since JJWT_RELEASE_VERSION, delegates to {@link #keyId(String)}. + * + * @param kid the case-sensitive JWS {@code kid} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see JWS Key ID + * @see JWE Key ID + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #keyId(String)} method. + */ + @Deprecated T setKeyId(String kid); /** - * Sets the header parameter names that use extensions to the JWT or JWA specification that MUST - * be understood and supported by the JWT recipient. A {@code null} value will remove the - * property from the JSON map. + * Deprecated as of JJWT_RELEASE_VERSION, there is no need to set this any longer as the {@code JwtBuilder} will + * always set the {@code alg} header as necessary. * - * @param crit the header parameter names that use extensions to the JWT or JWA specification that MUST - * be understood and supported by the JWT recipient. - * @return the header for method chaining. - * @see JWS crit (Critical) Header Parameter - * @see JWS crit (Critical) Header Parameter + * @param alg the JWS or JWE algorithm {@code alg} value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @since 0.1 + * @deprecated since JJWT_RELEASE_VERSION and will be removed before the 1.0 release. */ - T setCritical(Set crit); + @Deprecated + T setAlgorithm(String alg); } diff --git a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java index eb78e008d..bbbd17a7a 100644 --- a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java +++ b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java @@ -44,7 +44,7 @@ * the {@link io.jsonwebtoken.SigningKeyResolverAdapter} and overriding only the method you need to support instead of * implementing this interface directly.

                      * - * @see io.jsonwebtoken.JwtParserBuilder#setKeyLocator(Locator) + * @see io.jsonwebtoken.JwtParserBuilder#keyLocator(Locator) * @since 0.4 * @deprecated since JJWT_RELEASE_VERSION. Implement {@link Locator} instead. */ diff --git a/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java b/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java index c3af881fe..6695f5acd 100644 --- a/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java +++ b/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java @@ -25,7 +25,7 @@ * *

                      As of JJWT JJWT_RELEASE_VERSION, various Resolver concepts (including the {@code SigningKeyResolver}) have been * unified into a single {@link Locator} interface. For key location, (for both signing and encryption keys), - * use the {@link JwtParserBuilder#setKeyLocator(Locator)} to configure a parser with your desired Key locator instead + * use the {@link JwtParserBuilder#keyLocator(Locator)} to configure a parser with your desired Key locator instead * of using a {@code SigningKeyResolver}. Also see {@link LocatorAdapter} for the Adapter pattern parallel of this * class. This {@code SigningKeyResolverAdapter} class will be removed before the 1.0 release.

                      * @@ -46,11 +46,11 @@ * are not overridden, one (or both) of the *KeyBytes variants must be overridden depending on your expected * use case. You do not have to override any method that does not represent an expected condition.

                      * - * @see io.jsonwebtoken.JwtParserBuilder#setKeyLocator(Locator) + * @see io.jsonwebtoken.JwtParserBuilder#keyLocator(Locator) * @see LocatorAdapter * @since 0.4 * @deprecated since JJWT_RELEASE_VERSION. Use {@link LocatorAdapter LocatorAdapter} with - * {@link JwtParserBuilder#setKeyLocator(Locator)} + * {@link JwtParserBuilder#keyLocator(Locator)} */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated diff --git a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java index 9a1feef94..98fa66746 100644 --- a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java +++ b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java @@ -29,6 +29,16 @@ */ public interface MapMutator> { + /** + * Removes the map entry with the specified key. + *

                      This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for + * method chaining.

                      + * + * @param key the key for the map entry to remove. + * @return the mutator/builder for method chaining. + */ + T delete(K key); + /** * Removes all entries from the map. The map will be empty after this call returns. *

                      This method is the same as {@link Map#clear Map.clear}, but instead returns the mutator instance for @@ -39,8 +49,9 @@ public interface MapMutator> { T empty(); /** - * Sets the specified name/value pair in the map. A {@code null} or empty value will remove the property - * from the map entirely. + * Sets the specified key/value pair in the map, overwriting any existing entry with the same key. + * A {@code null} or empty value will remove the entry from the map entirely. + * *

                      This method is the same as {@link Map#put Map.put}, but instead returns the mutator instance for * method chaining.

                      * @@ -48,26 +59,17 @@ public interface MapMutator> { * @param value the value to set for the specified header parameter name * @return the mutator/builder for method chaining. */ - T set(K key, V value); + T add(K key, V value); /** - * Sets the specified name/value pairs in the map. If any name has a {@code null} or empty value, that - * map entry will be removed from the map entirely. + * Sets the specified key/value pairs in the map, overwriting any existing entries with the same keys. + * If any pair has a {@code null} or empty value, that pair will be removed from the map entirely. + * *

                      This method is the same as {@link Map#putAll Map.putAll}, but instead returns the mutator instance for * method chaining.

                      * * @param m the map to add * @return the mutator/builder for method chaining. */ - T set(Map m); - - /** - * Removes the map entry with the specified key. - *

                      This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for - * method chaining.

                      - * - * @param key the key for the map entry to remove. - * @return the mutator/builder for method chaining. - */ - T delete(K key); + T add(Map m); } diff --git a/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java index 7fd6f8b4e..5c7f0a595 100644 --- a/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java @@ -51,7 +51,7 @@ * and algorithm parameters required by that algorithm. For example:

                      * *
                      
                      - *     SecretKey key = aeadAlgorithm.keyBuilder().build();
                      + *     SecretKey key = aeadAlgorithm.key().build();
                        * 
                      * *

                      The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for diff --git a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java index cf106351c..cf0e29b15 100644 --- a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java @@ -69,7 +69,7 @@ public interface AsymmetricJwkBuilder, * *

                      Per * JWK RFC 7517, Section 4.3, last paragraph, - * the {@code use} (Public Key Use) and {@link #setOperations(Set) key_ops (Key Operations)} members + * the {@code use} (Public Key Use) and {@link #operations(Set) key_ops (Key Operations)} members * SHOULD NOT be used together; however, if both are used, the information they convey MUST be * consistent. Applications should specify which of these members they use, if either is to be used by the * application.

                      @@ -78,5 +78,5 @@ public interface AsymmetricJwkBuilder, * @return the builder for method chaining. * @throws IllegalArgumentException if the {@code use} value is {@code null} or empty. */ - T setPublicKeyUse(String use) throws IllegalArgumentException; + T publicKeyUse(String use) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java similarity index 64% rename from api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java rename to api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java index fd4b7d886..5ac13fecf 100644 --- a/api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java @@ -28,14 +28,56 @@ import java.util.List; /** - * A prototypical {@link JwkBuilder} that coerces to a more type-specific builder based on the {@link Key} that will - * be represented as a JWK. + * A {@link JwkBuilder} that coerces to a more type-specific builder based on the {@link Key} that will be + * represented as a JWK. * * @param the type of Java {@link Key} represented by the created {@link Jwk}. * @param the type of {@link Jwk} created by the builder * @since JJWT_RELEASE_VERSION */ -public interface ProtoJwkBuilder> extends JwkBuilder> { +public interface DynamicJwkBuilder> extends JwkBuilder> { + + /** + * Ensures the builder will create a {@link PublicJwk} for the specified Java {@link X509Certificate} chain. + * The first {@code X509Certificate} in the chain (at array index 0) MUST contain a {@link PublicKey} + * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. + * + *

                      This method is provided for congruence with the other {@code chain} methods and is expected to be used when + * the calling code has a variable {@code PublicKey} reference. Based on the argument type, it will + * delegate to one of the following methods if possible: + *

                        + *
                      • {@link #rsaChain(List)}
                      • + *
                      • {@link #ecChain(List)}
                      • + *
                      • {@link #octetChain(List)}
                      • + *
                      + * + *

                      If the specified {@code chain} argument is not capable of being supported by one of those methods, an + * {@link UnsupportedKeyException} will be thrown.

                      + * + *

                      Type Parameters

                      + * + *

                      In addition to the public key type A, the public key's associated private key type + * B is parameterized as well. This ensures that any subsequent call to the builder's + * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

                      + * + *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>chain(edECPublicKeyX509CertificateChain)
                      +     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                      +     *     ... etc ...
                      +     *     .build();
                      + * + * @param the type of {@link PublicKey} provided by the created public JWK. + * @param the type of {@link PrivateKey} that may be paired with the {@link PublicKey} to produce a + * {@link PrivateJwk} if desired. + * @param chain the {@link X509Certificate} chain to inspect to find the {@link PublicKey} to represent as a + * {@link PublicJwk}. + * @return the builder coerced as a {@link PublicJwkBuilder} for continued method chaining. + * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to + * other {@code key} methods. + * @see PublicJwk + * @see PrivateJwk + */ + PublicJwkBuilder chain(List chain) + throws UnsupportedKeyException; /** * Ensures the builder will create a {@link SecretJwk} for the specified Java {@link SecretKey}. @@ -43,7 +85,7 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link SecretKey} to represent as a {@link SecretJwk}. * @return the builder coerced as a {@link SecretJwkBuilder}. */ - SecretJwkBuilder forKey(SecretKey key); + SecretJwkBuilder key(SecretKey key); /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link RSAPublicKey}. @@ -51,20 +93,20 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link RSAPublicKey} to represent as a {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPublicJwkBuilder}. */ - RsaPublicJwkBuilder forKey(RSAPublicKey key); + RsaPublicJwkBuilder key(RSAPublicKey key); /** * Ensures the builder will create an {@link RsaPrivateJwk} for the specified Java {@link RSAPrivateKey}. If * possible, it is recommended to also call the resulting builder's - * {@link RsaPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method with the private key's matching + * {@link RsaPrivateJwkBuilder#publicKey(PublicKey) publicKey} method with the private key's matching * {@link PublicKey} for better performance. See the - * {@link RsaPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} and {@link PrivateJwk} JavaDoc for more + * {@link RsaPrivateJwkBuilder#publicKey(PublicKey) publicKey} and {@link PrivateJwk} JavaDoc for more * information. * * @param key the {@link RSAPublicKey} to represent as a {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPrivateJwkBuilder}. */ - RsaPrivateJwkBuilder forKey(RSAPrivateKey key); + RsaPrivateJwkBuilder key(RSAPrivateKey key); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link ECPublicKey}. @@ -72,31 +114,30 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link ECPublicKey} to represent as a {@link EcPublicJwk}. * @return the builder coerced as an {@link EcPublicJwkBuilder}. */ - EcPublicJwkBuilder forKey(ECPublicKey key); + EcPublicJwkBuilder key(ECPublicKey key); /** * Ensures the builder will create an {@link EcPrivateJwk} for the specified Java {@link ECPrivateKey}. If * possible, it is recommended to also call the resulting builder's - * {@link EcPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method with the private key's matching + * {@link EcPrivateJwkBuilder#publicKey(PublicKey) publicKey} method with the private key's matching * {@link PublicKey} for better performance. See the - * {@link EcPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} and {@link PrivateJwk} JavaDoc for more + * {@link EcPrivateJwkBuilder#publicKey(PublicKey) publicKey} and {@link PrivateJwk} JavaDoc for more * information. * * @param key the {@link ECPublicKey} to represent as an {@link EcPublicJwk}. * @return the builder coerced as a {@link EcPrivateJwkBuilder}. */ - EcPrivateJwkBuilder forKey(ECPrivateKey key); - + EcPrivateJwkBuilder key(ECPrivateKey key); /** * Ensures the builder will create a {@link PublicJwk} for the specified Java {@link PublicKey} argument. This - * method is provided for congruence with the other {@code forKey} methods and is expected to be used when + * method is provided for congruence with the other {@code key} methods and is expected to be used when * the calling code has an untyped {@code PublicKey} reference. Based on the argument type, it will delegate to one * of the following methods if possible: *
                        - *
                      • {@link #forKey(RSAPublicKey)}
                      • - *
                      • {@link #forKey(ECPublicKey)}
                      • - *
                      • {@link #forOctetKey(PublicKey)}
                      • + *
                      • {@link #key(RSAPublicKey)}
                      • + *
                      • {@link #key(ECPublicKey)}
                      • + *
                      • {@link #octetKey(PublicKey)}
                      • *
                      * *

                      If the specified {@code key} argument is not capable of being supported by one of those methods, an @@ -106,10 +147,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

                      In addition to the public key type A, the public key's associated private key type * B is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PublicJwkBuilder#setPrivateKey(PrivateKey) setPrivateKey} method will be type-safe. For example:

                      + * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

                      * - *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPublicKey)
                      -     *     .setPrivateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                      +     * 
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPublicKey)
                      +     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                            *     ... etc ...
                            *     .build();
                      * @@ -119,21 +160,21 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link PublicKey} to represent as a {@link PublicJwk}. * @return the builder coerced as a {@link PublicJwkBuilder} for continued method chaining. * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to - * other {@code forKey} methods. + * other {@code key} methods. * @see PublicJwk * @see PrivateJwk */ -
                      PublicJwkBuilder forKey(A key) throws UnsupportedKeyException; + PublicJwkBuilder key(A key) throws UnsupportedKeyException; /** * Ensures the builder will create a {@link PrivateJwk} for the specified Java {@link PrivateKey} argument. This - * method is provided for congruence with the other {@code forKey} methods and is expected to be used when + * method is provided for congruence with the other {@code key} methods and is expected to be used when * the calling code has an untyped {@code PrivateKey} reference. Based on the argument type, it will delegate to one * of the following methods if possible: *
                        - *
                      • {@link #forKey(RSAPrivateKey)}
                      • - *
                      • {@link #forKey(ECPrivateKey)}
                      • - *
                      • {@link #forOctetKey(PrivateKey)}
                      • + *
                      • {@link #key(RSAPrivateKey)}
                      • + *
                      • {@link #key(ECPrivateKey)}
                      • + *
                      • {@link #octetKey(PrivateKey)}
                      • *
                      * *

                      If the specified {@code key} argument is not capable of being supported by one of those methods, an @@ -143,10 +184,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

                      In addition to the private key type B, the private key's associated public key type * A is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method will be type-safe. For example:

                      + * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

                      * - *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPrivateKey)
                      -     *     .setPublicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                      +     * 
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPrivateKey)
                      +     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                            *     ... etc ...
                            *     .build();
                      * @@ -155,11 +196,50 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link PrivateKey} to represent as a {@link PrivateJwk}. * @return the builder coerced as a {@link PrivateJwkBuilder} for continued method chaining. * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to - * other {@code forKey} methods. + * other {@code key} methods. + * @see PublicJwk + * @see PrivateJwk + */ +
                      PrivateJwkBuilder key(B key) throws UnsupportedKeyException; + + /** + * Ensures the builder will create a {@link PrivateJwk} for the specified Java {@link KeyPair} argument. This + * method is provided for congruence with the other {@code keyPair} methods and is expected to be used when + * the calling code has a variable {@code PrivateKey} reference. Based on the argument's {@code PrivateKey} type, + * it will delegate to one of the following methods if possible: + *
                        + *
                      • {@link #key(RSAPrivateKey)}
                      • + *
                      • {@link #key(ECPrivateKey)}
                      • + *
                      • {@link #octetKey(PrivateKey)}
                      • + *
                      + *

                      and automatically set the resulting builder's {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} with + * the pair's {@code PublicKey}.

                      + * + *

                      If the specified {@code key} argument is not capable of being supported by one of those methods, an + * {@link UnsupportedKeyException} will be thrown.

                      + * + *

                      Type Parameters

                      + * + *

                      In addition to the private key type B, the private key's associated public key type + * A is parameterized as well. This ensures that any subsequent call to the builder's + * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

                      + * + *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>keyPair(anEdECKeyPair)
                      +     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                      +     *     ... etc ...
                      +     *     .build();
                      + * + * @param
                      the {@code keyPair} argument's {@link PublicKey} type + * @param the {@code keyPair} argument's {@link PrivateKey} type + * @param keyPair the {@code KeyPair} containing the public and private key + * @return the builder coerced as a {@link PrivateJwkBuilder} for continued method chaining. + * @throws UnsupportedKeyException if the specified {@code KeyPair}'s keys are not supported and cannot be used to + * delegate to other {@code key} methods. * @see PublicJwk * @see PrivateJwk */ - PrivateJwkBuilder forKey(B key) throws UnsupportedKeyException; + PrivateJwkBuilder keyPair(KeyPair keyPair) + throws UnsupportedKeyException; /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Edwards-curve {@code PublicKey} @@ -175,10 +255,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

                      In addition to the public key type A, the public key's associated private key type * B is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PublicJwkBuilder#setPrivateKey(PrivateKey) setPrivateKey} method will be type-safe. For example:

                      + * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

                      * - *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPublicKey)
                      -     *     .setPrivateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                      +     * 
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPublicKey)
                      +     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                            *     ... etc ...
                            *     .build();
                      * @@ -191,7 +271,7 @@ public interface ProtoJwkBuilder> extends JwkBui * @see
                      java.security.interfaces.XECPublicKey * @see java.security.interfaces.EdECPublicKey */ - OctetPublicJwkBuilder forOctetKey(A key); + OctetPublicJwkBuilder octetKey(A key); /** * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Edwards-curve {@code PrivateKey} @@ -209,10 +289,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

                      In addition to the private key type B, the private key's associated public key type * A is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method will be type-safe. For example:

                      + * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

                      * - *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPrivateKey)
                      -     *     .setPublicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                      +     * 
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPrivateKey)
                      +     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                            *     ... etc ...
                            *     .build();
                      * @@ -225,64 +305,38 @@ public interface ProtoJwkBuilder> extends JwkBui * @see
                      java.security.interfaces.XECPrivateKey * @see java.security.interfaces.EdECPrivateKey */ - OctetPrivateJwkBuilder forOctetKey(A key); - - /** - * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve - * {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} MUST be an - * Edwards-curve public key as defined by {@link #forOctetKey(PublicKey)}. The pair's - * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by - * {@link #forOctetKey(PrivateKey)}. - * - * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. - * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. - * @param keyPair the Edwards-curve {@link KeyPair} to represent as an {@link OctetPrivateJwk}. - * @return the builder coerced as an {@link OctetPrivateJwkBuilder} for continued method chaining. - * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key - * instances. - */ - OctetPrivateJwkBuilder forOctetKeyPair(KeyPair keyPair); + OctetPrivateJwkBuilder octetKey(A key); /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. * The first {@code X509Certificate} in the chain (at list index 0) MUST * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by - * {@link #forOctetKey(PublicKey)}. - * - * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. - * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce - * an {@link OctetPrivateJwk} if desired. - * @param chain the {@link X509Certificate} chain to inspect to find the Edwards-curve {@code PublicKey} to - * represent as an {@link OctetPublicJwk}. - * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. - */ - OctetPublicJwkBuilder forOctetChain(List chain); - - /** - * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST - * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by - * {@link #forOctetKey(PublicKey)}. + * {@link #octetKey(PublicKey)}. * - * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. - * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce - * an {@link OctetPrivateJwk} if desired. + * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. + * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce + * an {@link OctetPrivateJwk} if desired. * @param chain the {@link X509Certificate} chain to inspect to find the Edwards-curve {@code PublicKey} to * represent as an {@link OctetPublicJwk}. * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. */ - OctetPublicJwkBuilder forOctetChain(X509Certificate... chain); + OctetPublicJwkBuilder octetChain(List chain); /** - * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST contain an {@link ECPublicKey} - * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. + * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve + * {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} MUST be an + * Edwards-curve public key as defined by {@link #octetKey(PublicKey)}. The pair's + * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by + * {@link #octetKey(PrivateKey)}. * - * @param chain the {@link X509Certificate} chain to inspect to find the {@link ECPublicKey} to represent as a - * {@link EcPublicJwk}. - * @return the builder coerced as an {@link EcPublicJwkBuilder}. + * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. + * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. + * @param keyPair the Edwards-curve {@link KeyPair} to represent as an {@link OctetPrivateJwk}. + * @return the builder coerced as an {@link OctetPrivateJwkBuilder} for continued method chaining. + * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key + * instances. */ - EcPublicJwkBuilder forEcChain(X509Certificate... chain); + OctetPrivateJwkBuilder octetKeyPair(KeyPair keyPair); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -293,7 +347,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link EcPublicJwk}. * @return the builder coerced as an {@link EcPublicJwkBuilder}. */ - EcPublicJwkBuilder forEcChain(List chain); + EcPublicJwkBuilder ecChain(List chain); /** * Ensures the builder will create an {@link EcPrivateJwk} for the specified Java Elliptic Curve @@ -306,18 +360,7 @@ public interface ProtoJwkBuilder> extends JwkBui * @throws IllegalArgumentException if the {@code keyPair} does not contain {@link ECPublicKey} and * {@link ECPrivateKey} instances. */ - EcPrivateJwkBuilder forEcKeyPair(KeyPair keyPair) throws IllegalArgumentException; - - /** - * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST contain an {@link RSAPublicKey} - * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. - * - * @param chain the {@link X509Certificate} chain to inspect to find the {@link RSAPublicKey} to represent as a - * {@link RsaPublicJwk}. - * @return the builder coerced as an {@link RsaPublicJwkBuilder}. - */ - RsaPublicJwkBuilder forRsaChain(X509Certificate... chain); + EcPrivateJwkBuilder ecKeyPair(KeyPair keyPair) throws IllegalArgumentException; /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -328,7 +371,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPublicJwkBuilder}. */ - RsaPublicJwkBuilder forRsaChain(List chain); + RsaPublicJwkBuilder rsaChain(List chain); /** * Ensures the builder will create an {@link RsaPrivateJwk} for the specified Java RSA @@ -341,5 +384,5 @@ public interface ProtoJwkBuilder> extends JwkBui * @throws IllegalArgumentException if the {@code keyPair} does not contain {@link RSAPublicKey} and * {@link RSAPrivateKey} instances. */ - RsaPrivateJwkBuilder forRsaKeyPair(KeyPair keyPair) throws IllegalArgumentException; + RsaPrivateJwkBuilder rsaKeyPair(KeyPair keyPair) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java index bb7227a5d..25aa92665 100644 --- a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java @@ -57,7 +57,7 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if {@code alg} is {@code null} or empty. */ - T setAlgorithm(String alg) throws IllegalArgumentException; + T algorithm(String alg) throws IllegalArgumentException; /** * Sets the JWK {@code kid} (Key ID) @@ -77,22 +77,22 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if the argument is {@code null} or empty. */ - T setId(String kid) throws IllegalArgumentException; + T id(String kid) throws IllegalArgumentException; /** - * Sets the JWK's {@link #setId(String) kid} value to be the Base64URL-encoding of its {@code SHA-256} + * Sets the JWK's {@link #id(String) kid} value to be the Base64URL-encoding of its {@code SHA-256} * {@link Jwk#thumbprint(HashAlgorithm) thumbprint}. That is, the constructed JWK's {@code kid} value will equal * jwk.{@link Jwk#thumbprint(HashAlgorithm) thumbprint}({@link Jwks.HASH}.{@link Jwks.HASH#SHA256 SHA256}).{@link JwkThumbprint#toString() toString()}. * - *

                      This is a convenience method that delegates to {@link #setIdFromThumbprint(HashAlgorithm)} using + *

                      This is a convenience method that delegates to {@link #idFromThumbprint(HashAlgorithm)} using * {@link Jwks.HASH}{@code .}{@link Jwks.HASH#SHA256 SHA256}.

                      * * @return the builder for method chaining. */ - T setIdFromThumbprint(); + T idFromThumbprint(); /** - * Sets the JWK's {@link #setId(String) kid} value to be the Base64URL-encoding of its + * Sets the JWK's {@link #id(String) kid} value to be the Base64URL-encoding of its * {@link Jwk#thumbprint(HashAlgorithm) thumbprint} using the specified {@link HashAlgorithm}. That is, the * constructed JWK's {@code kid} value will equal * {@link Jwk#thumbprint(HashAlgorithm) thumbprint}(alg).{@link JwkThumbprint#toString() toString()}. @@ -101,7 +101,7 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @see Jwks.HASH */ - T setIdFromThumbprint(HashAlgorithm alg); + T idFromThumbprint(HashAlgorithm alg); /** * Sets the JWK
                      {@code key_ops} @@ -174,5 +174,5 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if {@code ops} is {@code null} or empty. */ - T setOperations(Set ops) throws IllegalArgumentException; + T operations(Set ops) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java b/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java index 7dd07f5e9..7390765f4 100644 --- a/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java @@ -25,7 +25,7 @@ * A builder to construct a {@link JwkParser}. Example usage: *
                        * Jwk<?> jwk = Jwks.parser()
                      - *         .setProvider(aJcaProvider)         // optional
                      + *         .provider(aJcaProvider)            // optional
                        *         .deserializeJsonWith(deserializer) // optional
                        *         .build()
                        *         .parse(jwkString);
                      @@ -42,7 +42,7 @@ public interface JwkParserBuilder extends Builder { * if the JCA subsystem preferred provider should be used. * @return the builder for method chaining. */ - JwkParserBuilder setProvider(Provider provider); + JwkParserBuilder provider(Provider provider); /** * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. The diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwks.java b/api/src/main/java/io/jsonwebtoken/security/Jwks.java index 3f502be48..22cfc2616 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Jwks.java +++ b/api/src/main/java/io/jsonwebtoken/security/Jwks.java @@ -40,7 +40,7 @@ public final class Jwks { private Jwks() { } //prevent instantiation - private static final String BUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultProtoJwkBuilder"; + private static final String BUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultDynamicJwkBuilder"; private static final String PARSERBUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultJwkParserBuilder"; @@ -54,7 +54,7 @@ private Jwks() { *
                            * Jwks.{@link Jwks#builder}()
                            *     // ... etc ...
                      -     *     .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // <---
                      +     *     .{@link JwkBuilder#idFromThumbprint(HashAlgorithm) idFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // <---
                            *     .build()
                      *

                      or

                      *
                      @@ -152,7 +152,7 @@ private HASH() {
                            *
                            * @return a new JWK builder instance, allowing for type-safe JWK builder coercion based on a provided key or key pair.
                            */
                      -    public static ProtoJwkBuilder builder() {
                      +    public static DynamicJwkBuilder builder() {
                               return Classes.newInstance(BUILDER_CLASSNAME);
                           }
                       
                      diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
                      index 29c1e53d2..97b3eb02a 100644
                      --- a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
                      +++ b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
                      @@ -22,8 +22,8 @@
                        * their associated cryptographic algorithm implementation.
                        *
                        * @param  type of {@link Key} created by the builder
                      - * @param  type of builder to create each time {@link #keyBuilder()} is called.
                      - * @see #keyBuilder()
                      + * @param  type of builder to create each time {@link #key()} is called.
                      + * @see #key()
                        * @see KeyBuilder
                        * @since JJWT_RELEASE_VERSION
                        */
                      @@ -36,5 +36,5 @@ public interface KeyBuilderSupplier> {
                            * @return a new {@link KeyBuilder} instance that will produce new secure-random keys with a length sufficient
                            * to be used by the component's associated cryptographic algorithm.
                            */
                      -    B keyBuilder();
                      +    B key();
                       }
                      diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
                      index a93bc5760..a6b79bda3 100644
                      --- a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
                      +++ b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
                      @@ -21,7 +21,7 @@
                        * Interface implemented by components that support building/creating new {@link KeyPair}s suitable for use with their
                        * associated cryptographic algorithm implementation.
                        *
                      - * @see #keyPairBuilder()
                      + * @see #keyPair()
                        * @see KeyPairBuilder
                        * @since JJWT_RELEASE_VERSION
                        */
                      @@ -34,5 +34,5 @@ public interface KeyPairBuilderSupplier {
                            * @return a new {@link KeyPairBuilder} that will create new secure-random {@link KeyPair}s with a length and
                            * parameters sufficient for use with the component's associated cryptographic algorithm.
                            */
                      -    KeyPairBuilder keyPairBuilder();
                      +    KeyPairBuilder keyPair();
                       }
                      diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java b/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java
                      index 050d784c6..f9fe51f0f 100644
                      --- a/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java
                      +++ b/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java
                      @@ -49,8 +49,7 @@ public interface KeyRequest extends Request {
                            * {@code KeyRequest}.  {@link KeyAlgorithm} implementations that generate an ephemeral {@code SecretKey} to use
                            * as what the JWE specification calls a
                            * "Content Encryption Key (CEK)" should call the {@code AeadAlgorithm}'s
                      -     * {@link AeadAlgorithm#keyBuilder() keyBuilder()} to obtain a builder that will create a key suitable for that
                      -     * exact {@code AeadAlgorithm}.
                      +     * {@link AeadAlgorithm#key() key()} builder to create a key suitable for that exact {@code AeadAlgorithm}.
                            *
                            * @return the {@link AeadAlgorithm} that will be called for encryption or decryption after processing the
                            * {@code KeyRequest}.
                      diff --git a/api/src/main/java/io/jsonwebtoken/security/Keys.java b/api/src/main/java/io/jsonwebtoken/security/Keys.java
                      index 024dd94e5..e0eeaa979 100644
                      --- a/api/src/main/java/io/jsonwebtoken/security/Keys.java
                      +++ b/api/src/main/java/io/jsonwebtoken/security/Keys.java
                      @@ -68,8 +68,8 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException {
                                       "is not secure enough for any JWT HMAC-SHA algorithm.  The JWT " +
                                       "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " +
                                       "size >= 256 bits (the key size must be greater than or equal to the hash " +
                      -                "output size).  Consider using the Jwts.SIG.HS256.keyBuilder() method (or HS384.keyBuilder() " +
                      -                "or HS512.keyBuilder()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA " +
                      +                "output size).  Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() " +
                      +                "or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA " +
                                       "algorithm.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
                               throw new WeakKeyException(msg);
                           }
                      @@ -78,12 +78,12 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException {
                            * 

                      Deprecation Notice

                      * *

                      As of JJWT JJWT_RELEASE_VERSION, symmetric (secret) key algorithm instances can generate a key of suitable - * length for that specific algorithm by calling their {@code keyBuilder()} method directly. For example:

                      + * length for that specific algorithm by calling their {@code key()} builder method directly. For example:

                      * *
                      
                      -     * {@link Jwts.SIG#HS256}.keyBuilder().build();
                      -     * {@link Jwts.SIG#HS384}.keyBuilder().build();
                      -     * {@link Jwts.SIG#HS512}.keyBuilder().build();
                      +     * {@link Jwts.SIG#HS256}.key().build();
                      +     * {@link Jwts.SIG#HS384}.key().build();
                      +     * {@link Jwts.SIG#HS512}.key().build();
                            * 
                      * *

                      Call those methods as needed instead of this static {@code secretKeyFor} helper method - the returned @@ -124,7 +124,7 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException { * @throws IllegalArgumentException for any input value other than {@link io.jsonwebtoken.SignatureAlgorithm#HS256}, * {@link io.jsonwebtoken.SignatureAlgorithm#HS384}, or {@link io.jsonwebtoken.SignatureAlgorithm#HS512} * @deprecated since JJWT_RELEASE_VERSION. Use your preferred {@link MacAlgorithm} instance's - * {@link MacAlgorithm#keyBuilder() keyBuilder()} method directly. + * {@link MacAlgorithm#key() key()} builder method directly. */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -135,21 +135,21 @@ public static SecretKey secretKeyFor(io.jsonwebtoken.SignatureAlgorithm alg) thr String msg = "The " + alg.name() + " algorithm does not support shared secret keys."; throw new IllegalArgumentException(msg); } - return ((MacAlgorithm) salg).keyBuilder().build(); + return ((MacAlgorithm) salg).key().build(); } /** *

                      Deprecation Notice

                      * *

                      As of JJWT JJWT_RELEASE_VERSION, asymmetric key algorithm instances can generate KeyPairs of suitable strength - * for that specific algorithm by calling their {@code keyPairBuilder()} method directly. For example:

                      + * for that specific algorithm by calling their {@code keyPair()} builder method directly. For example:

                      * *
                      -     * Jwts.SIG.{@link Jwts.SIG#RS256 RS256}.keyPairBuilder().build();
                      -     * Jwts.SIG.{@link Jwts.SIG#RS384 RS384}.keyPairBuilder().build();
                      -     * Jwts.SIG.{@link Jwts.SIG#RS512 RS512}.keyPairBuilder().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS256 RS256}.keyPair().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS384 RS384}.keyPair().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS512 RS512}.keyPair().build();
                            * ... etc ...
                      -     * Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPairBuilder().build();
                      + * Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPair().build();
                      * *

                      Call those methods as needed instead of this static {@code keyPairFor} helper method - the returned * {@link KeyPairBuilder} allows callers to specify a preferred Provider or SecureRandom on the builder if @@ -229,7 +229,7 @@ public static SecretKey secretKeyFor(io.jsonwebtoken.SignatureAlgorithm alg) thr * @throws IllegalArgumentException if {@code alg} is not an asymmetric algorithm * @deprecated since JJWT_RELEASE_VERSION in favor of your preferred * {@link io.jsonwebtoken.security.SignatureAlgorithm} instance's - * {@link SignatureAlgorithm#keyPairBuilder() keyPairBuilder()} method directly. + * {@link SignatureAlgorithm#keyPair() keyPair()} builder method directly. */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -241,7 +241,7 @@ public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws throw new IllegalArgumentException(msg); } SignatureAlgorithm asalg = ((SignatureAlgorithm) salg); - return asalg.keyPairBuilder().build(); + return asalg.keyPair().build(); } /** @@ -264,7 +264,7 @@ public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws * @see Password#toCharArray() * @since JJWT_RELEASE_VERSION */ - public static Password forPassword(char[] password) { - return Classes.invokeStatic(BRIDGE_CLASS, "forPassword", FOR_PASSWORD_ARG_TYPES, new Object[]{password}); + public static Password password(char[] password) { + return Classes.invokeStatic(BRIDGE_CLASS, "password", FOR_PASSWORD_ARG_TYPES, new Object[]{password}); } } diff --git a/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java index bbb1bc0ef..3d04e9747 100644 --- a/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java @@ -47,7 +47,7 @@ * have a sufficient length and any algorithm parameters required by that algorithm. For example:

                      * *
                      - * SecretKey key = macAlgorithm.keyBuilder().build();
                      + * SecretKey key = macAlgorithm.key().build();
                      * *

                      The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for * that exact {@code MacAlgorithm} instance.

                      diff --git a/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java index f51e14b9b..c9bdb3fcf 100644 --- a/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java @@ -26,7 +26,7 @@ * @param the type of {@link PrivateJwk} created * @param the type of {@link PublicJwk} paired with the created private JWK. * @param the type of the builder, for subtype method chaining - * @see #setPublicKey(PublicKey) + * @see #publicKey(PublicKey) * @since JJWT_RELEASE_VERSION */ public interface PrivateJwkBuilderAs discussed in the {@link PrivateJwk} documentation, the JWK and JWA specifications require private JWKs to * contain both private key and public key data. If a public key is not provided via this - * {@code setPublicKey} method, the builder implementation must go through the work to derive the + * {@code publicKey} method, the builder implementation must go through the work to derive the * {@code PublicKey} instance based on the {@code PrivateKey} to obtain the necessary public key information.

                      * *

                      Calling this method with the {@code PrivateKey}'s matching {@code PublicKey} instance eliminates the need @@ -49,5 +49,5 @@ public interface PrivateJwkBuilder the type of {@link PrivateJwk} that matches the created {@link PublicJwk} * @param

                      the type of {@link PrivateJwkBuilder} that matches this builder if a {@link PrivateJwk} is desired. * @param the type of the builder, for subtype method chaining - * @see #setPrivateKey(PrivateKey) + * @see #privateKey(PrivateKey) * @since JJWT_RELEASE_VERSION */ public interface PublicJwkBuilder The type of object that will be created each time {@link #build()} is invoked. - * @see #setProvider(Provider) - * @see #setRandom(SecureRandom) + * @see #provider(Provider) + * @see #random(SecureRandom) * @since JJWT_RELEASE_VERSION */ public interface SecurityBuilder> extends Builder { @@ -38,7 +38,7 @@ public interface SecurityBuilder> extends Bui * @param provider the JCA Security Provider instance to use if necessary when building the new instance. * @return the builder for method chaining. */ - B setProvider(Provider provider); + B provider(Provider provider); /** * Sets the {@link SecureRandom} to use if necessary when calling {@link #build()}. This is an optional property @@ -47,5 +47,5 @@ public interface SecurityBuilder> extends Bui * @param random the {@link SecureRandom} instance to use if necessary when building the new instance. * @return the builder for method chaining. */ - B setRandom(SecureRandom random); + B random(SecureRandom random); } diff --git a/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java index f9d1aa445..b20192e81 100644 --- a/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java @@ -38,7 +38,7 @@ * required by that algorithm. For example:

                      * *
                      - * KeyPair pair = signatureAlgorithm.keyPairBuilder().build();
                      + * KeyPair pair = signatureAlgorithm.keyPair().build();
                      * *

                      The resulting {@code pair} is guaranteed to have the correct algorithm parameters and length/strength necessary * for that exact {@code signatureAlgorithm} instance.

                      diff --git a/api/src/main/java/io/jsonwebtoken/security/X509Builder.java b/api/src/main/java/io/jsonwebtoken/security/X509Builder.java index 99a7551d0..215dd48f8 100644 --- a/api/src/main/java/io/jsonwebtoken/security/X509Builder.java +++ b/api/src/main/java/io/jsonwebtoken/security/X509Builder.java @@ -28,8 +28,8 @@ public interface X509Builder> extends X509Mutator { /** * If the {@code enable} argument is {@code true}, compute the SHA-1 thumbprint of the first - * {@link X509Certificate} in the configured {@link #setX509CertificateChain(List) x509CertificateChain}, and set - * the resulting value as the {@link #setX509CertificateSha1Thumbprint(byte[])} parameter. + * {@link X509Certificate} in the configured {@link #x509CertificateChain(List) x509CertificateChain}, and set + * the resulting value as the {@link #x509CertificateSha1Thumbprint(byte[])} parameter. * *

                      If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a * {@code x5t} value.

                      @@ -42,8 +42,8 @@ public interface X509Builder> extends X509Mutator { /** * If the {@code enable} argument is {@code true}, compute the SHA-256 thumbprint of the first - * {@link X509Certificate} in the configured {@link #setX509CertificateChain(List) x509CertificateChain}, and set - * the resulting value as the {@link #setX509CertificateSha256Thumbprint(byte[])} parameter. + * {@link X509Certificate} in the configured {@link #x509CertificateChain(List) x509CertificateChain}, and set + * the resulting value as the {@link #x509CertificateSha256Thumbprint(byte[])} parameter. * *

                      If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a * {@code x5t#S256} value.

                      diff --git a/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java b/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java index 2fa241f8d..cd72d0b3a 100644 --- a/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java +++ b/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java @@ -62,7 +62,7 @@ public interface X509Mutator> { * @see JWS x5u (X.509 URL) Header Parameter * @see JWE x5u (X.509 URL) Header Parameter */ - T setX509Url(URI uri); + T x509Url(URI uri); /** * Sets the {@code x5c} (X.509 Certificate Chain) of the associated JWT or JWK. A {@code null} value will remove the @@ -85,7 +85,7 @@ public interface X509Mutator> { * @see JWS x5c (X.509 Certificate Chain) Header Parameter * @see JWE x5c (X.509 Certificate Chain) Header Parameter */ - T setX509CertificateChain(List chain); + T x509CertificateChain(List chain); /** * Sets the {@code x5t} (X.509 Certificate SHA-1 Thumbprint) (a.k.a. digest) of the DER-encoding of the @@ -111,7 +111,7 @@ public interface X509Mutator> { * @see JWS x5t (X.509 Certificate SHA-1 Thumbprint) Header Parameter * @see JWE x5t (X.509 Certificate SHA-1 Thumbprint) Header Parameter */ - T setX509CertificateSha1Thumbprint(byte[] thumbprint); + T x509CertificateSha1Thumbprint(byte[] thumbprint); /** * Sets the {@code x5t#S256} (X.509 Certificate SHA-256 Thumbprint) (a.k.a. digest) of the DER-encoding of the @@ -137,5 +137,5 @@ public interface X509Mutator> { * @see JWS x5t#S256 (X.509 Certificate SHA-256 Thumbprint) Header Parameter * @see JWE x5t#S256 (X.509 Certificate SHA-256 Thumbprint) Header Parameter */ - T setX509CertificateSha256Thumbprint(byte[] thumbprint); + T x509CertificateSha256Thumbprint(byte[] thumbprint); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java b/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java index 202aeffea..93ebc65c8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java @@ -41,7 +41,7 @@ public URI getX509Url() { } @Override - public T setX509Url(URI uri) { + public T x509Url(URI uri) { put(AbstractAsymmetricJwk.X5U, uri); return self(); } @@ -52,7 +52,7 @@ public List getX509CertificateChain() { } @Override - public T setX509CertificateChain(List chain) { + public T x509CertificateChain(List chain) { put(AbstractAsymmetricJwk.X5C, chain); return self(); } @@ -63,7 +63,7 @@ public byte[] getX509CertificateSha1Thumbprint() { } @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { put(AbstractAsymmetricJwk.X5T, thumbprint); return self(); } @@ -74,7 +74,7 @@ public byte[] getX509CertificateSha256Thumbprint() { } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { put(AbstractAsymmetricJwk.X5T_S256, thumbprint); return self(); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java index 4d5643e2b..0b45ea73f 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java @@ -17,60 +17,16 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.ClaimsBuilder; -import io.jsonwebtoken.impl.lang.DelegatingMapMutator; -import io.jsonwebtoken.impl.lang.Field; - -import java.util.Date; /** * @since JJWT_RELEASE_VERSION */ @SuppressWarnings("unused") // used via reflection via Jwts.claims() -public final class DefaultClaimsBuilder extends DelegatingMapMutator +public final class DefaultClaimsBuilder extends DelegatingClaimsMutator implements ClaimsBuilder { public DefaultClaimsBuilder() { - super(new FieldMap(DefaultClaims.FIELDS)); - } - - ClaimsBuilder put(Field field, Object value) { - this.DELEGATE.put(field, value); - return self(); - } - - @Override - public ClaimsBuilder setIssuer(String iss) { - return put(DefaultClaims.ISSUER, iss); - } - - @Override - public ClaimsBuilder setSubject(String sub) { - return put(DefaultClaims.SUBJECT, sub); - } - - @Override - public ClaimsBuilder setAudience(String aud) { - return put(DefaultClaims.AUDIENCE, aud); - } - - @Override - public ClaimsBuilder setExpiration(Date exp) { - return put(DefaultClaims.EXPIRATION, exp); - } - - @Override - public ClaimsBuilder setNotBefore(Date nbf) { - return put(DefaultClaims.NOT_BEFORE, nbf); - } - - @Override - public ClaimsBuilder setIssuedAt(Date iat) { - return put(DefaultClaims.ISSUED_AT, iat); - } - - @Override - public ClaimsBuilder setId(String jti) { - return put(DefaultClaims.JTI, jti); + super(); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java index 0e543ef15..cdc816a5e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java @@ -29,8 +29,8 @@ public class DefaultJwe

                      extends DefaultProtectedJwt implements private final byte[] iv; - public DefaultJwe(JweHeader header, P body, byte[] iv, byte[] aadTag) { - super(header, body, aadTag, DIGEST_NAME); + public DefaultJwe(JweHeader header, P payload, byte[] iv, byte[] aadTag) { + super(header, payload, aadTag, DIGEST_NAME); this.iv = Assert.notEmpty(iv, "Initialization vector cannot be null or empty."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java index bbefc9c04..462128aa1 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java @@ -67,19 +67,29 @@ public void clear() { // JWT Header methods // ============================================================= +// @Override +// public T algorithm(String alg) { +// return put(DefaultHeader.ALGORITHM, alg); +// } + @Override - public T setAlgorithm(String alg) { - return put(DefaultHeader.ALGORITHM, alg); + public T contentType(String cty) { + return put(DefaultHeader.CONTENT_TYPE, cty); } @Override - public T setContentType(String cty) { - return put(DefaultHeader.CONTENT_TYPE, cty); + public T type(String typ) { + return put(DefaultHeader.TYPE, typ); } @Override public T setType(String typ) { - return put(DefaultHeader.TYPE, typ); + return type(typ); + } + + @Override + public T setContentType(String cty) { + return contentType(cty); } @Override @@ -92,51 +102,60 @@ public T setCompressionAlgorithm(String zip) { // ============================================================= @Override - public T setJwkSetUrl(URI uri) { - return put(DefaultProtectedHeader.JKU, uri); + public T critical(Set crit) { + return put(DefaultProtectedHeader.CRIT, crit); } @Override - public T setJwk(PublicJwk jwk) { + public T jwk(PublicJwk jwk) { return put(DefaultProtectedHeader.JWK, jwk); } @Override - public T setKeyId(String kid) { + public T jwkSetUrl(URI uri) { + return put(DefaultProtectedHeader.JKU, uri); + } + + @Override + public T keyId(String kid) { return put(DefaultProtectedHeader.KID, kid); } @Override - public T setCritical(Set crit) { - return put(DefaultProtectedHeader.CRIT, crit); + public T setKeyId(String kid) { + return keyId(kid); } + @Override + public T setAlgorithm(String alg) { + return put(DefaultHeader.ALGORITHM, alg); + } // ============================================================= // X.509 methods // ============================================================= @Override - public T setX509Url(URI uri) { - this.x509.setX509Url(uri); + public T x509Url(URI uri) { + this.x509.x509Url(uri); return self(); } @Override - public T setX509CertificateChain(List chain) { - this.x509.setX509CertificateChain(chain); + public T x509CertificateChain(List chain) { + this.x509.x509CertificateChain(chain); return self(); } @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha1Thumbprint(thumbprint); + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha1Thumbprint(thumbprint); return self(); } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha256Thumbprint(thumbprint); + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha256Thumbprint(thumbprint); return self(); } @@ -145,27 +164,27 @@ public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { // ============================================================= @Override - public T setAgreementPartyUInfo(byte[] info) { + public T agreementPartyUInfo(byte[] info) { return put(DefaultJweHeader.APU, info); } @Override - public T setAgreementPartyUInfo(String info) { - return setAgreementPartyUInfo(Strings.utf8(Strings.clean(info))); + public T agreementPartyUInfo(String info) { + return agreementPartyUInfo(Strings.utf8(Strings.clean(info))); } @Override - public T setAgreementPartyVInfo(byte[] info) { + public T agreementPartyVInfo(byte[] info) { return put(DefaultJweHeader.APV, info); } @Override - public T setAgreementPartyVInfo(String info) { - return setAgreementPartyVInfo(Strings.utf8(Strings.clean(info))); + public T agreementPartyVInfo(String info) { + return agreementPartyVInfo(Strings.utf8(Strings.clean(info))); } @Override - public T setPbes2Count(int count) { + public T pbes2Count(int count) { return put(DefaultJweHeader.P2C, count); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java index ce53dcad6..f97dfe0cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java @@ -25,8 +25,8 @@ public class DefaultJws

                      extends DefaultProtectedJwt implements private final String signature; - public DefaultJws(JwsHeader header, P body, String signature) { - super(header, body, Decoders.BASE64URL.decode(signature), DIGEST_NAME); + public DefaultJws(JwsHeader header, P payload, String signature) { + super(header, payload, Decoders.BASE64URL.decode(signature), DIGEST_NAME); this.signature = signature; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 9800dfacf..b9f6061cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -15,8 +15,7 @@ */ package io.jsonwebtoken.impl; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ClaimsBuilder; +import io.jsonwebtoken.Header; import io.jsonwebtoken.JweHeader; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; @@ -38,6 +37,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Objects; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.AeadRequest; import io.jsonwebtoken.security.AeadResult; @@ -63,14 +63,15 @@ public class DefaultJwtBuilder implements JwtBuilder { - public static final String PUB_KEY_SIGN_MSG = "PublicKeys may not be used to create digital signatures. " + "Only PrivateKeys may be used to create digital signatures, and PublicKeys are used to verify " + "digital signatures."; + public static final String PUB_KEY_SIGN_MSG = "PublicKeys may not be used to create digital signatures. " + + "Only PrivateKeys may be used to create digital signatures, and PublicKeys are used to verify " + + "digital signatures."; protected Provider provider; protected SecureRandom secureRandom; - private final DefaultJwtBuilderHeader headerBuilder = new DefaultJwtBuilderHeader(this); - - private final ClaimsBuilder claimsBuilder = new DefaultClaimsBuilder(); + private final DefaultBuilderHeader headerBuilder; + private final DefaultBuilderClaims claimsBuilder; protected byte[] content; @@ -89,22 +90,32 @@ public class DefaultJwtBuilder implements JwtBuilder { protected Function, byte[]> headerSerializer; protected Function, byte[]> claimsSerializer; - protected Encoder base64UrlEncoder = Encoders.BASE64URL; + protected Encoder encoder = Encoders.BASE64URL; protected CompressionAlgorithm compressionAlgorithm; + public DefaultJwtBuilder() { + this.headerBuilder = new DefaultBuilderHeader(this); + this.claimsBuilder = new DefaultBuilderClaims(this); + } + @Override - public JwtBuilder.Header header() { + public BuilderHeader header() { return this.headerBuilder; } @Override - public JwtBuilder setProvider(Provider provider) { + public BuilderClaims claims() { + return this.claimsBuilder; + } + + @Override + public JwtBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public JwtBuilder setSecureRandom(SecureRandom secureRandom) { + public JwtBuilder random(SecureRandom secureRandom) { this.secureRandom = secureRandom; return this; } @@ -130,6 +141,11 @@ public byte[] apply(Map stringMap) { @Override public JwtBuilder serializeToJsonWith(final Serializer> serializer) { + return serializer(serializer); + } + + @Override + public JwtBuilder serializer(Serializer> serializer) { Assert.notNull(serializer, "Serializer cannot be null."); this.serializer = serializer; this.headerSerializer = wrap(serializer, "header"); @@ -138,29 +154,30 @@ public JwtBuilder serializeToJsonWith(final Serializer> serialize } @Override - public JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder) { - Assert.notNull(base64UrlEncoder, "base64UrlEncoder cannot be null."); - this.base64UrlEncoder = base64UrlEncoder; + public JwtBuilder base64UrlEncodeWith(Encoder encoder) { + return encoder(encoder); + } + + @Override + public JwtBuilder encoder(Encoder encoder) { + Assert.notNull(encoder, "encoder cannot be null."); + this.encoder = encoder; return this; } @Override public JwtBuilder setHeader(Map map) { - this.headerBuilder.clear(); - this.headerBuilder.putAll(map); - return this; + return this.headerBuilder.empty().add(map).and(); } @Override public JwtBuilder setHeaderParams(Map params) { - this.headerBuilder.putAll(params); - return this; + return this.headerBuilder.add(params).and(); } @Override public JwtBuilder setHeaderParam(String name, Object value) { - this.headerBuilder.put(name, value); - return this; + return this.headerBuilder.add(name, value).and(); } @SuppressWarnings("unchecked") // TODO: remove for 1.0 @@ -227,7 +244,8 @@ public JwtBuilder signWith(Key key, io.jsonwebtoken.SignatureAlgorithm alg) thro public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, byte[] secretKeyBytes) throws InvalidKeyException { Assert.notNull(alg, "SignatureAlgorithm cannot be null."); Assert.notEmpty(secretKeyBytes, "secret key byte array cannot be null or empty."); - Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); + Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. " + + "If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); SecretKey key = new SecretKeySpec(secretKeyBytes, alg.getJcaName()); return signWith(key, alg); } @@ -236,7 +254,8 @@ public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, byte[] secret @Override public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, String base64EncodedSecretKey) throws InvalidKeyException { Assert.hasText(base64EncodedSecretKey, "base64-encoded secret key cannot be null or empty."); - Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); + Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. " + + "If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); byte[] bytes = Decoders.BASE64.decode(base64EncodedSecretKey); return signWith(alg, bytes); } @@ -293,90 +312,119 @@ public JwtBuilder compressWith(CompressionAlgorithm alg) { @Override public JwtBuilder setPayload(String payload) { - byte[] bytes = payload != null ? payload.getBytes(StandardCharsets.UTF_8) : null; - return setContent(bytes); + return content(Strings.utf8(payload)); } @Override - public JwtBuilder setContent(byte[] content) { + public JwtBuilder content(byte[] content) { this.content = content; return this; } @Override - public JwtBuilder setContent(byte[] content, String cty) { + public JwtBuilder content(byte[] content, String cty) { Assert.notEmpty(content, "content byte array cannot be null or empty."); Assert.hasText(cty, "Content Type String cannot be null or empty."); cty = CompactMediaTypeIdConverter.INSTANCE.applyFrom(cty); - this.headerBuilder.setContentType(cty); - return setContent(content); - } - - @Override - public JwtBuilder setClaims(Claims claims) { - Assert.notNull(claims, "Claims argument cannot be null."); - return setClaims((Map) claims); + this.headerBuilder.contentType(cty); + return content(content); } @Override public JwtBuilder setClaims(Map claims) { Assert.notNull(claims, "Claims map cannot be null."); - this.claimsBuilder.empty(); - this.claimsBuilder.set(claims); - return this; + return this.claimsBuilder.empty().add(claims).and(); } @Override public JwtBuilder addClaims(Map claims) { - this.claimsBuilder.set(claims); - return this; + return claims(claims); + } + + @Override + public JwtBuilder claims(Map claims) { + return claims().add(claims).and(); + } + + @Override + public JwtBuilder claim(String name, Object value) { + return claims().add(name, value).and(); } @Override public JwtBuilder setIssuer(String iss) { - this.claimsBuilder.setIssuer(iss); + return issuer(iss); + } + + @Override + public JwtBuilder issuer(String iss) { + this.claimsBuilder.issuer(iss); return this; } @Override public JwtBuilder setSubject(String sub) { - this.claimsBuilder.setSubject(sub); + return subject(sub); + } + + @Override + public JwtBuilder subject(String sub) { + this.claimsBuilder.subject(sub); return this; } @Override public JwtBuilder setAudience(String aud) { - this.claimsBuilder.setAudience(aud); + return audience(aud); + } + + @Override + public JwtBuilder audience(String aud) { + this.claimsBuilder.audience(aud); return this; } @Override public JwtBuilder setExpiration(Date exp) { - this.claimsBuilder.setExpiration(exp); + return expiration(exp); + } + + @Override + public JwtBuilder expiration(Date exp) { + this.claimsBuilder.expiration(exp); return this; } @Override public JwtBuilder setNotBefore(Date nbf) { - this.claimsBuilder.setNotBefore(nbf); + return notBefore(nbf); + } + + @Override + public JwtBuilder notBefore(Date nbf) { + this.claimsBuilder.notBefore(nbf); return this; } @Override public JwtBuilder setIssuedAt(Date iat) { - this.claimsBuilder.setIssuedAt(iat); + return issuedAt(iat); + } + + @Override + public JwtBuilder issuedAt(Date iat) { + this.claimsBuilder.issuedAt(iat); return this; } @Override public JwtBuilder setId(String jti) { - this.claimsBuilder.setId(jti); - return this; + return id(jti); } @Override - public JwtBuilder claim(String name, Object value) { - this.claimsBuilder.set(name, value); + public JwtBuilder id(String jti) { + this.claimsBuilder.id(jti); return this; } @@ -390,7 +438,7 @@ public String compact() { throw new IllegalStateException(msg); } - final Claims claims = this.claimsBuilder.build(); + final io.jsonwebtoken.Claims claims = this.claimsBuilder.build(); if (Objects.isEmpty(content) && Collections.isEmpty(claims)) { if (jwe) { // JWE payload can never be empty: @@ -406,7 +454,7 @@ public String compact() { if (this.serializer == null) { // try to find one based on the services available //noinspection unchecked - serializeToJsonWith(Services.loadFirst(Serializer.class)); + serializer(Services.loadFirst(Serializer.class)); } byte[] payload = content; @@ -415,7 +463,7 @@ public String compact() { } if (!Objects.isEmpty(payload) && compressionAlgorithm != null) { payload = compressionAlgorithm.compress(payload); - this.headerBuilder.setCompressionAlgorithm(compressionAlgorithm.getId()); + this.headerBuilder.add(DefaultHeader.COMPRESSION_ALGORITHM.getId(), compressionAlgorithm.getId()); } if (jwe) { @@ -425,25 +473,17 @@ public String compact() { } } - private io.jsonwebtoken.Header buildHeader() { - return new DefaultJwtHeaderBuilder(this.headerBuilder).build(); - } - private String compact(byte[] payload) { Assert.stateNotNull(sigAlg, "SignatureAlgorithm is required."); // invariant -// if (this.key != null && !(header instanceof JwsHeader)) { -// header = new DefaultJwsHeader(header); -// } + this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), sigAlg.getId()); - this.headerBuilder.setAlgorithm(sigAlg.getId()); - - final io.jsonwebtoken.Header header = buildHeader(); + final Header header = this.headerBuilder.build(); byte[] headerBytes = headerSerializer.apply(header); - String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes); - String base64UrlEncodedBody = base64UrlEncoder.encode(payload); + String base64UrlEncodedHeader = encoder.encode(headerBytes); + String base64UrlEncodedBody = encoder.encode(payload); String jwt = base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedBody; @@ -453,7 +493,7 @@ private String compact(byte[] payload) { byte[] data = jwt.getBytes(StandardCharsets.US_ASCII); SecureRequest request = new DefaultSecureRequest<>(data, provider, secureRandom, key); byte[] signature = signFunction.apply(request); - String base64UrlSignature = base64UrlEncoder.encode(signature); + String base64UrlSignature = encoder.encode(signature); jwt += DefaultJwtParser.SEPARATOR_CHAR + base64UrlSignature; } else { // no signature (unprotected JWT), but must terminate w/ a period, see @@ -483,13 +523,13 @@ private String encrypt(byte[] payload) { SecretKey cek = Assert.notNull(keyResult.getKey(), "KeyResult must return a content encryption key."); byte[] encryptedCek = Assert.notNull(keyResult.getPayload(), "KeyResult must return an encrypted key byte array, even if empty."); - this.headerBuilder.setAlgorithm(keyAlg.getId()); + this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), keyAlg.getId()); this.headerBuilder.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId()); - final io.jsonwebtoken.Header header = buildHeader(); + final Header header = this.headerBuilder.build(); byte[] headerBytes = this.headerSerializer.apply(header); - final String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes); + final String base64UrlEncodedHeader = encoder.encode(headerBytes); byte[] aad = base64UrlEncodedHeader.getBytes(StandardCharsets.US_ASCII); AeadRequest encRequest = new DefaultAeadRequest(payload, provider, secureRandom, cek, aad); @@ -499,20 +539,43 @@ private String encrypt(byte[] payload) { byte[] ciphertext = Assert.notEmpty(encResult.getPayload(), "Encryption result must have non-empty ciphertext (result.getData())."); byte[] tag = Assert.notEmpty(encResult.getDigest(), "Encryption result must have a non-empty authentication tag."); - String base64UrlEncodedEncryptedCek = base64UrlEncoder.encode(encryptedCek); - String base64UrlEncodedIv = base64UrlEncoder.encode(iv); - String base64UrlEncodedCiphertext = base64UrlEncoder.encode(ciphertext); - String base64UrlEncodedTag = base64UrlEncoder.encode(tag); + String base64UrlEncodedEncryptedCek = encoder.encode(encryptedCek); + String base64UrlEncodedIv = encoder.encode(iv); + String base64UrlEncodedCiphertext = encoder.encode(ciphertext); + String base64UrlEncodedTag = encoder.encode(tag); + + return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedTag; + } + + private static class DefaultBuilderClaims extends DelegatingClaimsMutator + implements BuilderClaims { + + private final JwtBuilder builder; + + private DefaultBuilderClaims(JwtBuilder builder) { + super(); + this.builder = builder; + } + + @Override + public JwtBuilder and() { + return this.builder; + } - return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedTag; + private io.jsonwebtoken.Claims build() { + return new DefaultClaims(this.DELEGATE); + } } - private static class DefaultJwtBuilderHeader extends DefaultJweHeaderBuilder

                      - implements JwtBuilder.Header { + private static class DefaultBuilderHeader extends DefaultJweHeaderBuilder implements BuilderHeader { private final JwtBuilder builder; - public DefaultJwtBuilderHeader(JwtBuilder builder) { + private DefaultBuilderHeader(JwtBuilder builder) { super(); this.builder = Assert.notNull(builder, "JwtBuilder cannot be null."); } @@ -521,5 +584,9 @@ public DefaultJwtBuilderHeader(JwtBuilder builder) { public JwtBuilder and() { return builder; } + + private Header build() { + return new DefaultJwtHeaderBuilder(this).build(); + } } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index 50c6ea6b9..940b0cf4e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -95,18 +95,17 @@ public class DefaultJwtParser implements JwtParser { "the compact JWE string is missing the required signature."; public static final String MISSING_JWE_DIGEST_MSG_FMT = "The JWE header references key management algorithm '%s' " + - "but the compact JWE string is missing the " + "required AAD authentication tag."; + "but the compact JWE string is missing the required AAD authentication tag."; - private static final String MISSING_ENC_MSG = "JWE header does not contain a required " + - "'enc' (Encryption Algorithm) header parameter. " + "This header parameter is mandatory per the JWE " + - "Specification, Section 4.1.2. See " + - "https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.2 for more information."; + private static final String MISSING_ENC_MSG = "JWE header does not contain a required 'enc' (Encryption " + + "Algorithm) header parameter. This header parameter is mandatory per the JWE Specification, " + + "Section 4.1.2. See https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.2 for more information."; private static final String UNSECURED_DISABLED_MSG_PREFIX = "Unsecured JWSs (those with an " + DefaultHeader.ALGORITHM + " header value of '" + Jwts.SIG.NONE.getId() + "') are disallowed by " + "default as mandated by https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6. If you wish to " + - "allow them to be parsed, call the JwtParserBuilder.enableUnsecuredJws() method (but please read the " + - "security considerations covered in that method's JavaDoc before doing so). Header: "; + "allow them to be parsed, call the JwtParserBuilder.enableUnsecured() method, but please read the " + + "security considerations covered in that method's JavaDoc before doing so. Header: "; private static final String JWE_NONE_MSG = "JWEs do not support key management " + DefaultHeader.ALGORITHM + " header value '" + Jwts.SIG.NONE.getId() + "' per " + @@ -121,15 +120,15 @@ public class DefaultJwtParser implements JwtParser { "against [Denial of Service attacks](" + "https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf). If you " + "wish to enable Unsecure JWS payload decompression, call the JwtParserBuilder." + - "enableUnsecuredDecompression() method (but please read the security considerations covered in that " + - "method's JavaDoc before doing so)."; + "enableUnsecuredDecompression() method, but please read the security considerations covered in that " + + "method's JavaDoc before doing so."; private final Provider provider; @SuppressWarnings("deprecation") private final SigningKeyResolver signingKeyResolver; - private final boolean enableUnsecuredJws; + private final boolean enableUnsecured; private final boolean enableUnsecuredDecompression; @@ -143,7 +142,7 @@ public class DefaultJwtParser implements JwtParser { private final Locator keyLocator; - private final Decoder base64UrlDecoder; + private final Decoder decoder; private final Deserializer> deserializer; @@ -157,7 +156,7 @@ public class DefaultJwtParser implements JwtParser { @SuppressWarnings("deprecation") DefaultJwtParser(Provider provider, SigningKeyResolver signingKeyResolver, - boolean enableUnsecuredJws, + boolean enableUnsecured, boolean enableUnsecuredDecompression, Locator keyLocator, Clock clock, @@ -171,14 +170,14 @@ public class DefaultJwtParser implements JwtParser { Collection> extraKeyAlgs, Collection extraEncAlgs) { this.provider = provider; - this.enableUnsecuredJws = enableUnsecuredJws; + this.enableUnsecured = enableUnsecured; this.enableUnsecuredDecompression = enableUnsecuredDecompression; this.signingKeyResolver = signingKeyResolver; this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null."); this.clock = Assert.notNull(clock, "Clock cannot be null."); this.allowedClockSkewMillis = allowedClockSkewMillis; - this.expectedClaims = Jwts.claims().set(expectedClaims); - this.base64UrlDecoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); + this.expectedClaims = Jwts.claims().add(expectedClaims); + this.decoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); this.deserializer = Assert.notNull(deserializer, "Deserializer cannot be null."); this.sigAlgFn = new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.SIG.get(), extraSigAlgs, MISSING_JWS_ALG_MSG); @@ -305,10 +304,10 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe } //re-create the jwt part without the signature. This is what is needed for signature verification: - String jwtWithoutSignature = tokenized.getProtected() + SEPARATOR_CHAR + tokenized.getBody(); + String jwtWithoutSignature = tokenized.getProtected() + SEPARATOR_CHAR + tokenized.getPayload(); byte[] data = jwtWithoutSignature.getBytes(StandardCharsets.US_ASCII); - byte[] signature = base64UrlDecode(tokenized.getDigest(), "JWS signature"); + byte[] signature = decode(tokenized.getDigest(), "JWS signature"); try { VerifySecureDigestRequest request = @@ -346,8 +345,8 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe } // =============== Header ================= - final byte[] headerBytes = base64UrlDecode(base64UrlHeader, "protected header"); - Map m = readValue(headerBytes, "protected header"); + final byte[] headerBytes = decode(base64UrlHeader, "protected header"); + Map m = deserialize(headerBytes, "protected header"); Header header; try { header = tokenized.createHeader(m); @@ -376,7 +375,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe throw new MalformedJwtException(JWE_NONE_MSG); } // Unsecured JWTs are disabled by default per the RFC: - if (!enableUnsecuredJws) { + if (!enableUnsecured) { String msg = UNSECURED_DISABLED_MSG_PREFIX + header; throw new UnsupportedJwtException(msg); } @@ -389,9 +388,9 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe throw new MalformedJwtException(msg); } - // =============== Body ================= - byte[] payload = base64UrlDecode(tokenized.getBody(), "payload"); - if (tokenized instanceof TokenizedJwe && Arrays.length(payload) == 0) { // Only JWS body can be empty per https://github.com/jwtk/jjwt/pull/540 + // =============== Payload ================= + byte[] payload = decode(tokenized.getPayload(), "payload"); + if (tokenized instanceof TokenizedJwe && Arrays.length(payload) == 0) { // Only JWS payload can be empty per https://github.com/jwtk/jjwt/pull/540 String msg = "Compact JWE strings MUST always contain a payload (ciphertext)."; throw new MalformedJwtException(msg); } @@ -406,7 +405,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe byte[] cekBytes = Bytes.EMPTY; //ignored unless using an encrypted key algorithm String base64Url = tokenizedJwe.getEncryptedKey(); if (Strings.hasText(base64Url)) { - cekBytes = base64UrlDecode(base64Url, "JWE encrypted key"); + cekBytes = decode(base64Url, "JWE encrypted key"); if (Arrays.length(cekBytes) == 0) { String msg = "Compact JWE string represents an encrypted key, but the key is empty."; throw new MalformedJwtException(msg); @@ -415,7 +414,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe base64Url = tokenizedJwe.getIv(); if (Strings.hasText(base64Url)) { - iv = base64UrlDecode(base64Url, "JWE Initialization Vector"); + iv = decode(base64Url, "JWE Initialization Vector"); } if (Arrays.length(iv) == 0) { String msg = "Compact JWE strings must always contain an Initialization Vector."; @@ -430,7 +429,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe base64Url = base64UrlDigest; //guaranteed to be non-empty via the `alg` + digest check above: Assert.hasText(base64Url, "JWE AAD Authentication Tag cannot be null or empty."); - tag = base64UrlDecode(base64Url, "JWE AAD Authentication Tag"); + tag = decode(base64Url, "JWE AAD Authentication Tag"); if (Arrays.length(tag) == 0) { String msg = "Compact JWE strings must always contain an AAD Authentication Tag."; throw new MalformedJwtException(msg); @@ -467,7 +466,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe payload = result.getPayload(); } else if (hasDigest && this.signingKeyResolver == null) { //TODO: for 1.0, remove the == null check - // not using a signing key resolver, so we can verify the signature before reading the body, which is + // not using a signing key resolver, so we can verify the signature before reading the payload, which is // always safer: verifySignature(tokenized, ((JwsHeader) header), alg, new LocatingKeyResolver(this.keyLocator), null, null); } @@ -490,7 +489,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe // parameter is performed by the JWS application." // && isLikelyJson(payload)) { // likely to be json, parse it: - Map claimsMap = readValue(payload, "claims"); + Map claimsMap = deserialize(payload, "claims"); try { claims = new DefaultClaims(claimsMap); } catch (Exception e) { @@ -708,16 +707,16 @@ public Jwe onClaimsJwe(Jwe jwe) { }); } - protected byte[] base64UrlDecode(String base64UrlEncoded, String name) { + protected byte[] decode(String base64UrlEncoded, String name) { try { - return base64UrlDecoder.decode(base64UrlEncoded); + return decoder.decode(base64UrlEncoded); } catch (DecodingException e) { String msg = "Invalid Base64Url " + name + ": " + base64UrlEncoded; throw new MalformedJwtException(msg, e); } } - protected Map readValue(byte[] bytes, final String name) { + protected Map deserialize(byte[] bytes, final String name) { try { return deserializer.deserialize(bytes); } catch (MalformedJwtException | DeserializationException e) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index 0b797bad3..795293693 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -36,8 +36,11 @@ import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import javax.crypto.SecretKey; import java.security.Key; +import java.security.PrivateKey; import java.security.Provider; +import java.security.PublicKey; import java.util.Collection; import java.util.Date; import java.util.LinkedHashSet; @@ -62,7 +65,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { private Provider provider; - private boolean enableUnsecuredJws = false; + private boolean enableUnsecured = false; private boolean enableUnsecuredDecompression = false; @@ -82,7 +85,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { @SuppressWarnings("deprecation") private CompressionCodecResolver compressionCodecResolver; - private Decoder base64UrlDecoder = Decoders.BASE64URL; + private Decoder decoder = Decoders.BASE64URL; private Deserializer> deserializer; @@ -96,8 +99,8 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { private Key decryptionKey; @Override - public JwtParserBuilder enableUnsecuredJws() { - this.enableUnsecuredJws = true; + public JwtParserBuilder enableUnsecured() { + this.enableUnsecured = true; return this; } @@ -108,22 +111,32 @@ public JwtParserBuilder enableUnsecuredDecompression() { } @Override - public JwtParserBuilder setProvider(Provider provider) { + public JwtParserBuilder provider(Provider provider) { this.provider = provider; return this; } @Override public JwtParserBuilder deserializeJsonWith(Deserializer> deserializer) { + return deserializer(deserializer); + } + + @Override + public JwtParserBuilder deserializer(Deserializer> deserializer) { Assert.notNull(deserializer, "deserializer cannot be null."); this.deserializer = deserializer; return this; } @Override - public JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder) { - Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); - this.base64UrlDecoder = base64UrlDecoder; + public JwtParserBuilder base64UrlDecodeWith(Decoder decoder) { + return decoder(decoder); + } + + @Override + public JwtParserBuilder decoder(Decoder decoder) { + Assert.notNull(decoder, "decoder cannot be null."); + this.decoder = decoder; return this; } @@ -173,12 +186,17 @@ public JwtParserBuilder requireNotBefore(Date notBefore) { public JwtParserBuilder require(String claimName, Object value) { Assert.hasText(claimName, "claim name cannot be null or empty."); Assert.notNull(value, "The value cannot be null for claim name: " + claimName); - expectedClaims.set(claimName, value); + expectedClaims.add(claimName, value); return this; } @Override public JwtParserBuilder setClock(Clock clock) { + return clock(clock); + } + + @Override + public JwtParserBuilder clock(Clock clock) { Assert.notNull(clock, "Clock instance cannot be null."); this.clock = clock; return this; @@ -186,6 +204,11 @@ public JwtParserBuilder setClock(Clock clock) { @Override public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException { + return clockSkewSeconds(seconds); + } + + @Override + public JwtParserBuilder clockSkewSeconds(long seconds) throws IllegalArgumentException { Assert.isTrue(seconds <= MAX_CLOCK_SKEW_MILLIS, MAX_CLOCK_SKEW_ILLEGAL_MSG); this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); return this; @@ -210,13 +233,31 @@ public JwtParserBuilder setSigningKey(final Key key) { } @Override - public JwtParserBuilder verifyWith(Key key) { + public JwtParserBuilder verifyWith(SecretKey key) { + return verifyWith((Key) key); + } + + @Override + public JwtParserBuilder verifyWith(PublicKey key) { + return verifyWith((Key) key); + } + + private JwtParserBuilder verifyWith(Key key) { this.signatureVerificationKey = Assert.notNull(key, "signature verification key cannot be null."); return this; } @Override - public JwtParserBuilder decryptWith(final Key key) { + public JwtParserBuilder decryptWith(SecretKey key) { + return decryptWith((Key) key); + } + + @Override + public JwtParserBuilder decryptWith(PrivateKey key) { + return decryptWith((Key) key); + } + + private JwtParserBuilder decryptWith(final Key key) { this.decryptionKey = Assert.notNull(key, "decryption key cannot be null."); return this; } @@ -229,23 +270,23 @@ public JwtParserBuilder addCompressionAlgorithms(Collection encAlgs) { - Assert.notEmpty(encAlgs, "Additional AeadAlgorithm collection cannot be null or empty."); - this.extraEncAlgs.addAll(encAlgs); + public JwtParserBuilder addEncryptionAlgorithms(Collection algs) { + Assert.notEmpty(algs, "Additional AeadAlgorithm collection cannot be null or empty."); + this.extraEncAlgs.addAll(algs); return this; } @Override - public JwtParserBuilder addSignatureAlgorithms(Collection> sigAlgs) { - Assert.notEmpty(sigAlgs, "Additional SignatureAlgorithm collection cannot be null or empty."); - this.extraSigAlgs.addAll(sigAlgs); + public JwtParserBuilder addSignatureAlgorithms(Collection> algs) { + Assert.notEmpty(algs, "Additional SignatureAlgorithm collection cannot be null or empty."); + this.extraSigAlgs.addAll(algs); return this; } @Override - public JwtParserBuilder addKeyAlgorithms(Collection> keyAlgs) { - Assert.notEmpty(keyAlgs, "Additional KeyAlgorithm collection cannot be null or empty."); - this.extraKeyAlgs.addAll(keyAlgs); + public JwtParserBuilder addKeyAlgorithms(Collection> algs) { + Assert.notEmpty(algs, "Additional KeyAlgorithm collection cannot be null or empty."); + this.extraKeyAlgs.addAll(algs); return this; } @@ -258,7 +299,7 @@ public JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResol } @Override - public JwtParserBuilder setKeyLocator(Locator keyLocator) { + public JwtParserBuilder keyLocator(Locator keyLocator) { this.keyLocator = Assert.notNull(keyLocator, "Key locator cannot be null."); return this; } @@ -304,8 +345,8 @@ public JwtParser build() { keyLocator = new ConstantKeyLocator(this.signatureVerificationKey, this.decryptionKey); } - if (!enableUnsecuredJws && enableUnsecuredDecompression) { - String msg = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecuredJws' is also " + + if (!enableUnsecured && enableUnsecuredDecompression) { + String msg = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecured' is also " + "configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications."; throw new IllegalStateException(msg); @@ -324,13 +365,13 @@ public JwtParser build() { return new DefaultJwtParser( provider, signingKeyResolver, - enableUnsecuredJws, + enableUnsecured, enableUnsecuredDecompression, keyLocator, clock, allowedClockSkewMillis, expClaims, - base64UrlDecoder, + decoder, new JwtDeserializer<>(deserializer), compressionCodecResolver, extraZipAlgs, diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java deleted file mode 100644 index 7ad8d9a81..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 jsonwebtoken.io - * - * 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 io.jsonwebtoken.impl; - -/** - * @deprecated since 0.10.0 - */ -@Deprecated //remove just before 1.0.0 release -public class DefaultTextCodecFactory implements TextCodecFactory { - - protected String getSystemProperty(String key) { - return System.getProperty(key); - } - - protected boolean isAndroid() { - - String name = getSystemProperty("java.vm.name"); - if (name != null) { - String lcase = name.toLowerCase(); - return lcase.contains("dalvik"); - } - - name = getSystemProperty("java.vm.vendor"); - if (name != null) { - String lcase = name.toLowerCase(); - return lcase.contains("android"); - } - - return false; - } - - - @Override - public TextCodec getTextCodec() { - - if (isAndroid()) { - return new AndroidBase64Codec(); - } - - return new Base64Codec(); - } -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java index 7f5887d6b..9a54b9b4e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java @@ -24,12 +24,12 @@ class DefaultTokenizedJwt implements TokenizedJwt { private final String protectedHeader; - private final String body; + private final String payload; private final String digest; - DefaultTokenizedJwt(String protectedHeader, String body, String digest) { + DefaultTokenizedJwt(String protectedHeader, String payload, String digest) { this.protectedHeader = protectedHeader; - this.body = body; + this.payload = payload; this.digest = digest; } @@ -39,8 +39,8 @@ public String getProtected() { } @Override - public String getBody() { - return this.body; + public String getPayload() { + return this.payload; } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java new file mode 100644 index 000000000..44227b2df --- /dev/null +++ b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java @@ -0,0 +1,111 @@ +/* + * Copyright © 2023 jsonwebtoken.io + * + * 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 io.jsonwebtoken.impl; + +import io.jsonwebtoken.ClaimsMutator; +import io.jsonwebtoken.impl.lang.DelegatingMapMutator; +import io.jsonwebtoken.impl.lang.Field; +import io.jsonwebtoken.lang.MapMutator; + +import java.util.Date; + +/** + * @param subclass type + * @since JJWT_RELEASE_VERSION + */ +public class DelegatingClaimsMutator & ClaimsMutator> + extends DelegatingMapMutator + implements ClaimsMutator { + + protected DelegatingClaimsMutator() { + super(new FieldMap(DefaultClaims.FIELDS)); + } + + T put(Field field, Object value) { + this.DELEGATE.put(field, value); + return self(); + } + + @Override + public T setIssuer(String iss) { + return issuer(iss); + } + + @Override + public T issuer(String iss) { + return put(DefaultClaims.ISSUER, iss); + } + + @Override + public T setSubject(String sub) { + return subject(sub); + } + + @Override + public T subject(String sub) { + return put(DefaultClaims.SUBJECT, sub); + } + + @Override + public T setAudience(String aud) { + return audience(aud); + } + + @Override + public T audience(String aud) { + return put(DefaultClaims.AUDIENCE, aud); + } + + @Override + public T setExpiration(Date exp) { + return expiration(exp); + } + + @Override + public T expiration(Date exp) { + return put(DefaultClaims.EXPIRATION, exp); + } + + @Override + public T setNotBefore(Date nbf) { + return notBefore(nbf); + } + + @Override + public T notBefore(Date nbf) { + return put(DefaultClaims.NOT_BEFORE, nbf); + } + + @Override + public T setIssuedAt(Date iat) { + return issuedAt(iat); + } + + @Override + public T issuedAt(Date iat) { + return put(DefaultClaims.ISSUED_AT, iat); + } + + @Override + public T setId(String jti) { + return id(jti); + } + + @Override + public T id(String jti) { + return put(DefaultClaims.JTI, jti); + } +} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java b/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java index 3b069eef3..2bb4752b3 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java @@ -47,9 +47,22 @@ public IdLocator(Field field, Registry registry, Collection all = new LinkedHashSet<>(Collections.size(registry) + Collections.size(extras)); + all.addAll(registry.values()); // defaults MUST come before extras to allow extras to override if necessary all.addAll(extras); - all.addAll(registry.values()); - this.registry = new IdRegistry<>(field.getName(), all); + + // The registry requires CaSe-SeNsItIvE keys on purpose - all JWA standard algorithm identifiers + // (JWS 'alg', JWE 'enc', JWK 'kty', etc) are all case-sensitive per via the following RFC language: + // + // This name is a case-sensitive ASCII string. Names may not match other registered names in a + // case-insensitive manner unless the Designated Experts state that there is a compelling reason to + // allow an exception. + // + // References: + // - JWS/JWE alg and JWE enc 'Algorithm Name': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.1.1 + // - JWE zip 'Compression Algorithm Value': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.3.1 + // - JWK '"kty" Parameter Value': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.4.1 + + this.registry = new IdRegistry<>(field.getName(), all); // do not use the caseSensitive ctor argument - must be false } private static String type(Header header) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java deleted file mode 100644 index a318060f1..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 jsonwebtoken.io - * - * 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 io.jsonwebtoken.impl; - -/** - * @deprecated since 0.10.0 - */ -@Deprecated -public interface TextCodecFactory { - - TextCodec getTextCodec(); -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java b/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java index e52cfdd5a..948e4f87f 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java @@ -33,7 +33,7 @@ public interface TokenizedJwt { * * @return the Payload for a JWS or Ciphertext for a JWE. */ - String getBody(); + String getPayload(); /** * Returns the Signature for JWS or AAD Tag for JWE. diff --git a/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java index b76c8445a..4a8cb0506 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java @@ -41,13 +41,13 @@ public T empty() { } @Override - public T set(K key, V value) { + public T add(K key, V value) { put(key, value); return self(); } @Override - public T set(Map m) { + public T add(Map m) { putAll(m); return self(); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java index 70a67a9d4..88d54dcf9 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java @@ -69,7 +69,7 @@ public AbstractAsymmetricJwkBuilder(JwkContext ctx) { } @Override - public T setPublicKeyUse(String use) { + public T publicKeyUse(String use) { Assert.hasText(use, "publicKeyUse cannot be null or empty."); this.DELEGATE.setPublicKeyUse(use); return self(); @@ -83,16 +83,16 @@ public T setKeyUseStrategy(KeyUseStrategy strategy) { */ @Override - public T setX509CertificateChain(List chain) { + public T x509CertificateChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty."); - this.x509.setX509CertificateChain(chain); + this.x509.x509CertificateChain(chain); return self(); } @Override - public T setX509Url(URI uri) { + public T x509Url(URI uri) { Assert.notNull(uri, "X509Url cannot be null."); - this.x509.setX509Url(uri); + this.x509.x509Url(uri); return self(); } @@ -105,14 +105,14 @@ public T withX509KeyUse(boolean enable) { */ @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha1Thumbprint(thumbprint); + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha1Thumbprint(thumbprint); return self(); } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha256Thumbprint(thumbprint); + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha256Thumbprint(thumbprint); return self(); } @@ -145,10 +145,10 @@ private abstract static class DefaultPublicJwkBuilder ctx); @@ -170,7 +170,7 @@ private abstract static class DefaultPrivateJwkBuilder JwkContext newContext(A key) { } @Override - public T setProvider(Provider provider) { + public T provider(Provider provider) { this.DELEGATE.setProvider(provider); return self(); } @Override - public T setRandom(SecureRandom random) { + public T random(SecureRandom random) { this.DELEGATE.setRandom(random); return self(); } @Override - public T setAlgorithm(String alg) { + public T algorithm(String alg) { Assert.hasText(alg, "Algorithm cannot be null or empty."); this.DELEGATE.setAlgorithm(alg); return self(); } @Override - public T setId(String id) { + public T id(String id) { Assert.hasText(id, "Id cannot be null or empty."); this.DELEGATE.setIdThumbprintAlgorithm(null); //clear out any previously set value this.DELEGATE.setId(id); @@ -81,12 +81,12 @@ public T setId(String id) { } @Override - public T setIdFromThumbprint() { - return setIdFromThumbprint(Jwks.HASH.SHA256); + public T idFromThumbprint() { + return idFromThumbprint(Jwks.HASH.SHA256); } @Override - public T setIdFromThumbprint(HashAlgorithm alg) { + public T idFromThumbprint(HashAlgorithm alg) { Assert.notNull(alg, "Thumbprint HashAlgorithm cannot be null."); Assert.notNull(alg.getId(), "Thumbprint HashAlgorithm ID cannot be null."); this.DELEGATE.setId(null); // clear out any previous value @@ -95,7 +95,7 @@ public T setIdFromThumbprint(HashAlgorithm alg) { } @Override - public T setOperations(Set ops) { + public T operations(Set ops) { Assert.notEmpty(ops, "Operations cannot be null or empty."); this.DELEGATE.setOperations(ops); return self(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java index c3301189b..892921897 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java @@ -81,7 +81,7 @@ public int getKeyBitLength() { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { return new DefaultSecretKeyBuilder(KEY_ALG_NAME, getKeyBitLength()); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java index 087fa8d3d..8e0785e6c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java @@ -92,8 +92,8 @@ protected Provider getProvider(Request request) { protected SecretKey generateKey(KeyRequest request) { AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null."); - SecretKeyBuilder builder = Assert.notNull(enc.keyBuilder(), "Request encryptionAlgorithm keyBuilder cannot be null."); - SecretKey key = builder.setProvider(getProvider(request)).setRandom(request.getSecureRandom()).build(); + SecretKeyBuilder builder = Assert.notNull(enc.key(), "Request encryptionAlgorithm KeyBuilder cannot be null."); + SecretKey key = builder.provider(getProvider(request)).random(request.getSecureRandom()).build(); return Assert.notNull(key, "Request encryptionAlgorithm SecretKeyBuilder cannot produce null keys."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java index 7598cf641..7e5195897 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java @@ -74,7 +74,7 @@ public String toString() { return ID; } - public KeyPairBuilder keyPairBuilder() { - return new DefaultKeyPairBuilder(this.JCA_NAME).setProvider(this.PROVIDER); + public KeyPairBuilder keyPair() { + return new DefaultKeyPairBuilder(this.JCA_NAME).provider(this.PROVIDER); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java similarity index 70% rename from impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java rename to impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java index b73ddfc60..3cba163f8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java @@ -15,16 +15,15 @@ */ package io.jsonwebtoken.impl.security; -import io.jsonwebtoken.lang.Arrays; import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Strings; +import io.jsonwebtoken.security.DynamicJwkBuilder; import io.jsonwebtoken.security.EcPrivateJwkBuilder; import io.jsonwebtoken.security.EcPublicJwkBuilder; import io.jsonwebtoken.security.Jwk; import io.jsonwebtoken.security.OctetPrivateJwkBuilder; import io.jsonwebtoken.security.OctetPublicJwkBuilder; import io.jsonwebtoken.security.PrivateJwkBuilder; -import io.jsonwebtoken.security.ProtoJwkBuilder; import io.jsonwebtoken.security.PublicJwkBuilder; import io.jsonwebtoken.security.RsaPrivateJwkBuilder; import io.jsonwebtoken.security.RsaPublicJwkBuilder; @@ -44,35 +43,35 @@ import java.util.List; @SuppressWarnings("unused") //used via reflection by io.jsonwebtoken.security.Jwks -public class DefaultProtoJwkBuilder> - extends AbstractJwkBuilder> implements ProtoJwkBuilder { +public class DefaultDynamicJwkBuilder> + extends AbstractJwkBuilder> implements DynamicJwkBuilder { - public DefaultProtoJwkBuilder() { + public DefaultDynamicJwkBuilder() { super(new DefaultJwkContext()); } @Override - public SecretJwkBuilder forKey(SecretKey key) { + public SecretJwkBuilder key(SecretKey key) { return new AbstractJwkBuilder.DefaultSecretJwkBuilder(newContext(key)); } @Override - public RsaPublicJwkBuilder forKey(RSAPublicKey key) { + public RsaPublicJwkBuilder key(RSAPublicKey key) { return new AbstractAsymmetricJwkBuilder.DefaultRsaPublicJwkBuilder(newContext(key)); } @Override - public RsaPrivateJwkBuilder forKey(RSAPrivateKey key) { + public RsaPrivateJwkBuilder key(RSAPrivateKey key) { return new AbstractAsymmetricJwkBuilder.DefaultRsaPrivateJwkBuilder(newContext(key)); } @Override - public EcPublicJwkBuilder forKey(ECPublicKey key) { + public EcPublicJwkBuilder key(ECPublicKey key) { return new AbstractAsymmetricJwkBuilder.DefaultEcPublicJwkBuilder(newContext(key)); } @Override - public EcPrivateJwkBuilder forKey(ECPrivateKey key) { + public EcPrivateJwkBuilder key(ECPrivateKey key) { return new AbstractAsymmetricJwkBuilder.DefaultEcPrivateJwkBuilder(newContext(key)); } @@ -84,14 +83,14 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { @SuppressWarnings("unchecked") @Override - public PublicJwkBuilder forKey(A key) { + public PublicJwkBuilder key(A key) { if (key instanceof RSAPublicKey) { - return (PublicJwkBuilder) forKey((RSAPublicKey) key); + return (PublicJwkBuilder) key((RSAPublicKey) key); } else if (key instanceof ECPublicKey) { - return (PublicJwkBuilder) forKey((ECPublicKey) key); + return (PublicJwkBuilder) key((ECPublicKey) key); } else { try { - return forOctetKey(key); + return octetKey(key); } catch (Exception e) { throw unsupportedKey(key, e); } @@ -100,15 +99,15 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { @SuppressWarnings("unchecked") @Override - public PrivateJwkBuilder forKey(B key) { + public PrivateJwkBuilder key(B key) { Assert.notNull(key, "Key cannot be null."); if (key instanceof RSAPrivateKey) { - return (PrivateJwkBuilder) forKey((RSAPrivateKey) key); + return (PrivateJwkBuilder) key((RSAPrivateKey) key); } else if (key instanceof ECPrivateKey) { - return (PrivateJwkBuilder) forKey((ECPrivateKey) key); + return (PrivateJwkBuilder) key((ECPrivateKey) key); } else { try { - return forOctetKey(key); + return octetKey(key); } catch (Exception e) { throw unsupportedKey(key, e); } @@ -116,84 +115,85 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { } @Override - public OctetPublicJwkBuilder forOctetKey(A key) { + public OctetPublicJwkBuilder octetKey(A key) { return new AbstractAsymmetricJwkBuilder.DefaultOctetPublicJwkBuilder<>(newContext(key)); } @Override - public OctetPrivateJwkBuilder forOctetKey(A key) { + public OctetPrivateJwkBuilder octetKey(A key) { return new AbstractAsymmetricJwkBuilder.DefaultOctetPrivateJwkBuilder<>(newContext(key)); } + @SuppressWarnings("unchecked") @Override - public RsaPublicJwkBuilder forRsaChain(X509Certificate... chain) { + public PublicJwkBuilder chain(List chain) + throws UnsupportedKeyException { Assert.notEmpty(chain, "chain cannot be null or empty."); - return forRsaChain(Arrays.asList(chain)); + X509Certificate cert = Assert.notNull(chain.get(0), "The first X509Certificate cannot be null."); + PublicKey key = Assert.notNull(cert.getPublicKey(), "The first X509Certificate's PublicKey cannot be null."); + return this.key((A)key).x509CertificateChain(chain); } @Override - public RsaPublicJwkBuilder forRsaChain(List chain) { + public RsaPublicJwkBuilder rsaChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); RSAPublicKey pubKey = KeyPairs.assertKey(key, RSAPublicKey.class, "The first X509Certificate's "); - return forKey(pubKey).setX509CertificateChain(chain); - } - - @Override - public EcPublicJwkBuilder forEcChain(X509Certificate... chain) { - Assert.notEmpty(chain, "chain cannot be null or empty."); - return forEcChain(Arrays.asList(chain)); + return key(pubKey).x509CertificateChain(chain); } @Override - public EcPublicJwkBuilder forEcChain(List chain) { + public EcPublicJwkBuilder ecChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); ECPublicKey pubKey = KeyPairs.assertKey(key, ECPublicKey.class, "The first X509Certificate's "); - return forKey(pubKey).setX509CertificateChain(chain); + return key(pubKey).x509CertificateChain(chain); } @SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls @Override - public OctetPrivateJwkBuilder forOctetKeyPair(KeyPair pair) { + public OctetPrivateJwkBuilder octetKeyPair(KeyPair pair) { PublicKey pub = KeyPairs.getKey(pair, PublicKey.class); PrivateKey priv = KeyPairs.getKey(pair, PrivateKey.class); EdwardsCurve.assertEdwards(pub); EdwardsCurve.assertEdwards(priv); - return (OctetPrivateJwkBuilder) forOctetKey(priv).setPublicKey(pub); - } - - @Override - public OctetPublicJwkBuilder forOctetChain(X509Certificate... chain) { - Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty."); - return forOctetChain(Arrays.asList(chain)); + return (OctetPrivateJwkBuilder) octetKey(priv).publicKey(pub); } @SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls @Override - public OctetPublicJwkBuilder forOctetChain(List chain) { + public OctetPublicJwkBuilder octetChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); Assert.notNull(key, "The first X509Certificate's PublicKey cannot be null."); EdwardsCurve.assertEdwards(key); - return this.forOctetKey((A) key).setX509CertificateChain(chain); + return this.octetKey((A) key).x509CertificateChain(chain); } @Override - public RsaPrivateJwkBuilder forRsaKeyPair(KeyPair pair) { + public RsaPrivateJwkBuilder rsaKeyPair(KeyPair pair) { RSAPublicKey pub = KeyPairs.getKey(pair, RSAPublicKey.class); RSAPrivateKey priv = KeyPairs.getKey(pair, RSAPrivateKey.class); - return forKey(priv).setPublicKey(pub); + return key(priv).publicKey(pub); } @Override - public EcPrivateJwkBuilder forEcKeyPair(KeyPair pair) { + public EcPrivateJwkBuilder ecKeyPair(KeyPair pair) { ECPublicKey pub = KeyPairs.getKey(pair, ECPublicKey.class); ECPrivateKey priv = KeyPairs.getKey(pair, ECPrivateKey.class); - return forKey(priv).setPublicKey(pub); + return key(priv).publicKey(pub); + } + + @SuppressWarnings("unchecked") + @Override + public PrivateJwkBuilder keyPair(KeyPair keyPair) + throws UnsupportedKeyException { + A pub = (A)KeyPairs.getKey(keyPair, PublicKey.class); + B priv = (B)KeyPairs.getKey(keyPair, PrivateKey.class); + return this.key(priv).publicKey(pub); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java index 864087893..86bdf8a88 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java @@ -59,9 +59,9 @@ public Jwk parse(String json) throws KeyException { JwkBuilder builder = Jwks.builder(); if (this.provider != null) { - builder.setProvider(this.provider); + builder.provider(this.provider); } - return builder.set(data).build(); + return builder.add(data).build(); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java index a2ed3a818..d71822be0 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java @@ -31,7 +31,7 @@ public class DefaultJwkParserBuilder implements JwkParserBuilder { private Deserializer> deserializer; @Override - public JwkParserBuilder setProvider(Provider provider) { + public JwkParserBuilder provider(Provider provider) { this.provider = provider; return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java index 9c70e0a1a..3d21081cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java @@ -50,13 +50,13 @@ public DefaultKeyPairBuilder(String jcaName, AlgorithmParameterSpec params) { } @Override - public KeyPairBuilder setProvider(Provider provider) { + public KeyPairBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public KeyPairBuilder setRandom(SecureRandom random) { + public KeyPairBuilder random(SecureRandom random) { this.random = random; return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java index d873d8bec..1fd7c0291 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java @@ -81,7 +81,7 @@ private boolean isJwaStandardJcaName(String jcaName) { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength()); } @@ -142,8 +142,8 @@ protected void validateKey(Key k, boolean signing) { msg += " The JWT " + "JWA Specification (RFC 7518, Section 3.2) states that keys used with " + id + " MUST have a " + "size >= " + minKeyBitLength + " bits (the key size must be greater than or equal to the hash " + - "output size). Consider using the Jwts.SIG." + id + ".keyBuilder() " + - "method to create a key guaranteed to be secure enough for " + id + ". See " + + "output size). Consider using the Jwts.SIG." + id + ".key() " + + "builder to create a key guaranteed to be secure enough for " + id + ". See " + "https://tools.ietf.org/html/rfc7518#section-3.2 for more information."; } else { //custom algorithm - just indicate required key length: msg += " The " + id + " algorithm requires keys to have a size >= " + minKeyBitLength + " bits."; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java index 63ead5912..c4f2002bc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java @@ -39,17 +39,17 @@ public DefaultSecretKeyBuilder(String jcaName, int bitLength) { throw new IllegalArgumentException(msg); } this.BIT_LENGTH = Assert.gt(bitLength, 0, "bitLength must be > 0"); - setRandom(Randoms.secureRandom()); + random(Randoms.secureRandom()); } @Override - public SecretKeyBuilder setProvider(Provider provider) { + public SecretKeyBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public SecretKeyBuilder setRandom(SecureRandom random) { + public SecretKeyBuilder random(SecureRandom random) { this.random = random != null ? random : Randoms.secureRandom(); return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java index 9b580107a..2ad9db553 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java @@ -61,7 +61,7 @@ public boolean contains(ECPoint point) { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(KEY_PAIR_GENERATOR_JCA_NAME, toParameterSpec()); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java index ccf137c2f..b5d65603c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java @@ -100,10 +100,10 @@ public EcSignatureAlgorithm(int orderBitLength) { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, this.KEY_PAIR_GEN_PARAMS) - .setProvider(getProvider()) - .setRandom(Randoms.secureRandom()); + .provider(getProvider()) + .random(Randoms.secureRandom()); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java index 84f6e19a7..3bc33858c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java @@ -25,6 +25,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.DecryptionKeyRequest; +import io.jsonwebtoken.security.DynamicJwkBuilder; import io.jsonwebtoken.security.EcPublicJwk; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.Jwks; @@ -33,7 +34,6 @@ import io.jsonwebtoken.security.KeyRequest; import io.jsonwebtoken.security.KeyResult; import io.jsonwebtoken.security.OctetPublicJwk; -import io.jsonwebtoken.security.ProtoJwkBuilder; import io.jsonwebtoken.security.PublicJwk; import io.jsonwebtoken.security.Request; import io.jsonwebtoken.security.SecureRequest; @@ -98,7 +98,7 @@ protected KeyPair generateKeyPair(final Request request, final ECParameterSpe //visible for testing, for Edwards elliptic curves protected KeyPair generateKeyPair(SecureRandom random, EdwardsCurve curve, Provider provider) { - return curve.keyPairBuilder().setProvider(provider).setRandom(random).build(); + return curve.keyPair().provider(provider).random(random).build(); } protected byte[] generateZ(final KeyRequest request, final PublicKey pub, final PrivateKey priv) { @@ -183,7 +183,7 @@ public KeyResult getEncryptionKey(KeyRequest request) throws Security KeyPair pair; // generated (ephemeral) key pair final SecureRandom random = ensureSecureRandom(request); - ProtoJwkBuilder jwkBuilder = Jwks.builder().setRandom(random); + DynamicJwkBuilder jwkBuilder = Jwks.builder().random(random); if (publicKey instanceof ECKey) { ECKey ecPublicKey = (ECKey) publicKey; @@ -204,13 +204,13 @@ public KeyResult getEncryptionKey(KeyRequest request) throws Security request.getHeader(), request.getEncryptionAlgorithm()); } pair = generateKeyPair(random, curve, provider); - jwkBuilder.setProvider(provider); + jwkBuilder.provider(provider); } Assert.stateNotNull(pair, "Internal implementation state: KeyPair cannot be null."); // This asserts that the generated public key (and therefore the request key) is on a JWK-supported curve: - PublicJwk jwk = jwkBuilder.forKey(pair.getPublic()).build(); + PublicJwk jwk = jwkBuilder.key(pair.getPublic()).build(); final SecretKey derived = deriveKey(request, publicKey, pair.getPrivate()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java index 590b84d74..c9d68b18a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java @@ -64,8 +64,8 @@ protected String getJcaName(Request request) { } @Override - public KeyPairBuilder keyPairBuilder() { - return this.preferredCurve.keyPairBuilder(); + public KeyPairBuilder keyPair() { + return this.preferredCurve.keyPair(); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java index e1c4ccd99..b5cd00ac2 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java @@ -357,8 +357,8 @@ public boolean isSignatureCurve() { } @Override - public KeyPairBuilder keyPairBuilder() { - return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).setProvider(getProvider()); + public KeyPairBuilder keyPair() { + return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).provider(getProvider()); } public static boolean isEdwards(Key key) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java index 453a9d1b7..5fccab1d4 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java @@ -51,7 +51,7 @@ public PublicKey apply(PrivateKey privateKey) { // Since we already have a private key, we provide a RNG that 'generates' the existing private key // instead of a random one, and the corresponding public key will be computed for us automatically. SecureRandom random = new ConstantRandom(pkBytes); - KeyPair pair = curve.keyPairBuilder().setRandom(random).build(); + KeyPair pair = curve.keyPair().random(random).build(); Assert.stateNotNull(pair, "Edwards curve generated keypair cannot be null."); return Assert.stateNotNull(pair.getPublic(), "Edwards curve KeyPair must have a PublicKey"); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java index 9ca92f564..e64527f21 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java @@ -66,7 +66,7 @@ public int getKeyBitLength() { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { // The Sun JCE KeyGenerator throws an exception if bitLengths are not standard AES 128, 192 or 256 values. // Since the JWA HmacAes algorithms require double that, we use secure-random keys instead: return new RandomSecretKeyBuilder(KEY_ALG_NAME, getKeyBitLength()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java index c1af66e4d..9955c7927 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java @@ -121,7 +121,7 @@ public T applyFrom(Object o) { throw new IllegalArgumentException(msg); } String skey = (String) key; - builder.set(skey, entry.getValue()); + builder.add(skey, entry.getValue()); } Jwk jwk = builder.build(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java index de7d5562a..eac7ccb9a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java @@ -30,7 +30,7 @@ public final class KeysBridge { private KeysBridge() { } - public static Password forPassword(char[] password) { + public static Password password(char[] password) { return new PasswordSpec(password); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java index c7dc1fc75..8e2f692e8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java @@ -78,10 +78,10 @@ public Signature get() throws Exception { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder("RSA", this.preferredKeyBitLength) - .setProvider(getProvider()) - .setRandom(Randoms.secureRandom()); + .provider(getProvider()) + .random(Randoms.secureRandom()); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java index 67a2ccc4a..c08e33626 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java @@ -144,8 +144,8 @@ public static int estimateIterations(KeyAlgorithm alg, long for (int i = 0; points.size() < NUM_SAMPLES; i++) { char[] password = randomChars(PASSWORD_LENGTH); - Password key = Keys.forPassword(password); - HEADER.setPbes2Count(workFactor); + Password key = Keys.password(password); + HEADER.pbes2Count(workFactor); KeyRequest request = new DefaultKeyRequest<>(null, null, key, HEADER, ENC_ALG); long start = System.currentTimeMillis(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java b/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java index 76f00fdb7..cc0d2e829 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java @@ -72,25 +72,25 @@ public X509BuilderSupport withX509Sha256Thumbprint(boolean enable) { } @Override - public X509BuilderSupport setX509Url(URI uri) { + public X509BuilderSupport x509Url(URI uri) { this.fieldMap.put(AbstractAsymmetricJwk.X5U.getId(), uri); return this; } @Override - public X509BuilderSupport setX509CertificateChain(List chain) { + public X509BuilderSupport x509CertificateChain(List chain) { this.fieldMap.put(AbstractAsymmetricJwk.X5C.getId(), chain); return this; } @Override - public X509BuilderSupport setX509CertificateSha1Thumbprint(byte[] thumbprint) { + public X509BuilderSupport x509CertificateSha1Thumbprint(byte[] thumbprint) { this.fieldMap.put(AbstractAsymmetricJwk.X5T.getId(), thumbprint); return this; } @Override - public X509BuilderSupport setX509CertificateSha256Thumbprint(byte[] thumbprint) { + public X509BuilderSupport x509CertificateSha256Thumbprint(byte[] thumbprint) { this.fieldMap.put(AbstractAsymmetricJwk.X5T_S256.getId(), thumbprint); return this; } @@ -118,11 +118,11 @@ public void apply() { if (firstCert != null) { if (computeX509Sha1Thumbprint) { byte[] thumbprint = computeThumbprint(firstCert, DefaultHashAlgorithm.SHA1); - setX509CertificateSha1Thumbprint(thumbprint); + x509CertificateSha1Thumbprint(thumbprint); } if (computeX509Sha256) { byte[] thumbprint = computeThumbprint(firstCert, Jwks.HASH.SHA256); - setX509CertificateSha256Thumbprint(thumbprint); + x509CertificateSha256Thumbprint(thumbprint); } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy index e5de114a0..a8d1b0d0f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy @@ -37,13 +37,13 @@ class CustomObjectDeserializationTest { String jwtString = Jwts.builder().claim("cust", customBean).compact() // no custom deserialization, object is a map - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(jwtString) + Jwt jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(jwtString) assertNotNull jwt assertEquals jwt.getPayload().get('cust'), [key1: 'value1', key2: 42] // custom type for 'cust' claim Deserializer deserializer = new JacksonDeserializer([cust: CustomBean]) - jwt = Jwts.parser().enableUnsecuredJws().deserializeJsonWith(deserializer).build().parseClaimsJwt(jwtString) + jwt = Jwts.parser().enableUnsecured().deserializeJsonWith(deserializer).build().parseClaimsJwt(jwtString) assertNotNull jwt CustomBean result = jwt.getPayload().get("cust", CustomBean) assertEquals customBean, result diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 90d7e3965..d994ea58f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -69,7 +69,7 @@ class JwtParserTest { String bad = base64Url('{"alg":"none"}') + '.' + base64Url(junkPayload) + '.' try { - Jwts.parser().enableUnsecuredJws().build().parse(bad) + Jwts.parser().enableUnsecured().build().parse(bad) fail() } catch (MalformedJwtException expected) { assertEquals 'Unable to read claims JSON: ' + junkPayload, expected.getMessage() @@ -129,7 +129,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) try { - Jwts.parser().enableUnsecuredJws().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().enableUnsecured().setSigningKey(randomKey()).build().parse(bad) fail() } catch (MalformedJwtException se) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.getMessage() @@ -202,7 +202,7 @@ class JwtParserTest { @Test void testParseNullPayloadWithoutKey() { String compact = Jwts.builder().compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parse(compact) + def jwt = Jwts.parser().enableUnsecured().build().parse(compact) assertEquals 'none', jwt.header.alg assertEquals '', new String(jwt.payload as byte[], StandardCharsets.UTF_8) } @@ -219,7 +219,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parser().enableUnsecuredJws().setClock(fixedClock).build().parse(compact) + Jwts.parser().enableUnsecured().setClock(fixedClock).build().parse(compact) fail() } catch (ExpiredJwtException e) { // https://github.com/jwtk/jjwt/issues/107 (the Z designator at the end of the timestamp): @@ -237,7 +237,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() try { - Jwts.parser().enableUnsecuredJws().build().parse(compact) + Jwts.parser().enableUnsecured().build().parse(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -254,7 +254,7 @@ class JwtParserTest { String subject = 'Joe' String compact = Jwts.builder().setSubject(subject).setExpiration(exp).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecured().setAllowedClockSkewSeconds(10).build().parse(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -266,7 +266,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecured().setAllowedClockSkewSeconds(1).build().parse(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -280,7 +280,7 @@ class JwtParserTest { String subject = 'Joe' String compact = Jwts.builder().setSubject(subject).setNotBefore(exp).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecured().setAllowedClockSkewSeconds(10).build().parse(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -292,7 +292,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(exp).compact() try { - Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecured().setAllowedClockSkewSeconds(1).build().parse(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -310,7 +310,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals payload, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -321,7 +321,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').compact() try { - Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + Jwts.parser().enableUnsecured().build().parseContentJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals e.getMessage(), 'Unprotected Claims JWTs are not supported.' @@ -368,7 +368,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -381,7 +381,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -427,7 +427,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -442,7 +442,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() try { - Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -480,7 +480,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -497,7 +497,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected Claims JWTs are not supported.', e.getMessage() @@ -593,7 +593,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseClaimsJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -610,7 +610,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key). + Jwts.parser().enableUnsecured().setSigningKey(key). build(). parseClaimsJws(compact) fail() @@ -1492,7 +1492,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() - Jwts.parser().enableUnsecuredJws().setClock(new FixedClock(beforeExpiry)).build().parse(compact) + Jwts.parser().enableUnsecured().setClock(new FixedClock(beforeExpiry)).build().parse(compact) } @Test @@ -1512,7 +1512,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() try { - Jwts.parser().enableUnsecuredJws().setClock(new DefaultClock()).build().parse(compact) + Jwts.parser().enableUnsecured().setClock(new DefaultClock()).build().parse(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -1585,7 +1585,7 @@ class JwtParserTest { String jwtStr = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(sig) try { - Jwts.parser().enableUnsecuredJws().build().parse(jwtStr) + Jwts.parser().enableUnsecured().build().parse(jwtStr) fail() } catch (MalformedJwtException se) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.message diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index c4dee7712..cc9b74e0d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -88,7 +88,7 @@ class JwtsTest { @Test void testHeaderWithMapArg() { - def header = Jwts.header().set([alg: "HS256"]).build() + def header = Jwts.header().add([alg: "HS256"]).build() assertTrue header instanceof DefaultJwsHeader assertEquals 'HS256', header.getAlgorithm() assertEquals 'HS256', header.alg @@ -165,8 +165,8 @@ class JwtsTest { void testSetContentWithContentType() { String s = 'Hello JJWT' String cty = 'text/plain' - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() + def jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals cty, jwt.header.getContentType() assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -176,8 +176,8 @@ class JwtsTest { String s = 'Hello JJWT' String subtype = 'foo' String cty = "application/$subtype" - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() + def jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals subtype, jwt.header.getContentType() // assert that the compact form was used assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -187,8 +187,8 @@ class JwtsTest { String s = 'Hello JJWT' String subtype = 'foo' String cty = "application/$subtype;part=1/2" - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() + def jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals cty, jwt.header.getContentType() // two slashes, can't compact assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -198,9 +198,9 @@ class JwtsTest { def claims = [iss: 'joe', exp: later(), 'https://example.com/is_root': true] - String jwt = Jwts.builder().setClaims(claims).compact() + String jwt = Jwts.builder().claims().add(claims).and().compact() - def token = Jwts.parser().enableUnsecuredJws().build().parse(jwt) + def token = Jwts.parser().enableUnsecured().build().parse(jwt) //noinspection GrEqualsBetweenInconvertibleTypes assert token.payload == claims @@ -230,7 +230,7 @@ class JwtsTest { String claims = Encoders.BASE64URL.encode(claimsJson.getBytes(StandardCharsets.UTF_8)) String compact = header + '.' + claims + '.' - def jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + def jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals 'none', jwt.header.getAlgorithm() assertEquals 'joe', jwt.payload.getSubject() } @@ -274,7 +274,7 @@ class JwtsTest { @Test void testParseWithHeaderOnly() { String unsecuredJwt = base64Url("{\"alg\":\"none\"}") + ".." - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parse(unsecuredJwt) + Jwt jwt = Jwts.parser().enableUnsecured().build().parse(unsecuredJwt) assertEquals "none", jwt.getHeader().get("alg") } @@ -290,12 +290,12 @@ class JwtsTest { @Test void testParseWithMissingRequiredSignature() { - Key key = Jwts.SIG.HS256.keyBuilder().build() + Key key = Jwts.SIG.HS256.key().build() String compact = Jwts.builder().setSubject('foo').signWith(key).compact() int i = compact.lastIndexOf('.') String missingSig = compact.substring(0, i + 1) try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(missingSig) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseClaimsJws(missingSig) fail() } catch (MalformedJwtException expected) { String s = String.format(DefaultJwtParser.MISSING_JWS_DIGEST_MSG_FMT, 'HS256') @@ -306,7 +306,7 @@ class JwtsTest { @Test void testWithInvalidCompressionAlgorithm() { try { - Jwts.builder().setHeaderParam(DefaultHeader.COMPRESSION_ALGORITHM.getId(), "CUSTOM").setId("andId").compact() + Jwts.builder().header().add('zip', 'CUSTOM').and().id("andId").compact() } catch (CompressionException e) { assertEquals "Unsupported compression algorithm 'CUSTOM'", e.getMessage() } @@ -315,7 +315,7 @@ class JwtsTest { @Test void testConvenienceIssuer() { String compact = Jwts.builder().setIssuer("Me").compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertEquals 'Me', claims.getIssuer() compact = Jwts.builder().setSubject("Joe") @@ -323,14 +323,14 @@ class JwtsTest { .setIssuer(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getIssuer() } @Test void testConvenienceSubject() { String compact = Jwts.builder().setSubject("Joe").compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertEquals 'Joe', claims.getSubject() compact = Jwts.builder().setIssuer("Me") @@ -338,14 +338,14 @@ class JwtsTest { .setSubject(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getSubject() } @Test void testConvenienceAudience() { String compact = Jwts.builder().setAudience("You").compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertEquals 'You', claims.getAudience() compact = Jwts.builder().setIssuer("Me") @@ -353,7 +353,7 @@ class JwtsTest { .setAudience(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getAudience() } @@ -361,7 +361,7 @@ class JwtsTest { void testConvenienceExpiration() { Date then = laterDate(10000) String compact = Jwts.builder().setExpiration(then).compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims def claimedDate = claims.getExpiration() assertEquals then, claimedDate @@ -370,7 +370,7 @@ class JwtsTest { .setExpiration(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getExpiration() } @@ -378,7 +378,7 @@ class JwtsTest { void testConvenienceNotBefore() { Date now = now() //jwt exp only supports *seconds* since epoch: String compact = Jwts.builder().setNotBefore(now).compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims def claimedDate = claims.getNotBefore() assertEquals now, claimedDate @@ -387,7 +387,7 @@ class JwtsTest { .setNotBefore(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getNotBefore() } @@ -395,7 +395,7 @@ class JwtsTest { void testConvenienceIssuedAt() { Date now = now() //jwt exp only supports *seconds* since epoch: String compact = Jwts.builder().setIssuedAt(now).compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims def claimedDate = claims.getIssuedAt() assertEquals now, claimedDate @@ -404,7 +404,7 @@ class JwtsTest { .setIssuedAt(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getIssuedAt() } @@ -412,7 +412,7 @@ class JwtsTest { void testConvenienceId() { String id = UUID.randomUUID().toString() String compact = Jwts.builder().setId(id).compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertEquals id, claims.getId() compact = Jwts.builder().setIssuer("Me") @@ -420,7 +420,7 @@ class JwtsTest { .setId(null) //null should remove it .compact() - claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getId() } @@ -428,7 +428,7 @@ class JwtsTest { void testUncompressedJwt() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -450,7 +450,7 @@ class JwtsTest { void testCompressedJwtWithDeflate() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -472,7 +472,7 @@ class JwtsTest { void testCompressedJwtWithGZIP() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -494,7 +494,7 @@ class JwtsTest { void testCompressedWithCustomResolver() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -533,7 +533,7 @@ class JwtsTest { void testCompressedJwtWithUnrecognizedHeader() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -552,7 +552,7 @@ class JwtsTest { void testCompressStringPayloadWithDeflate() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String payload = "this is my test for a payload" @@ -673,8 +673,8 @@ class JwtsTest { void testParseClaimsJwsWithWeakHmacKey() { def alg = Jwts.SIG.HS384 - def key = alg.keyBuilder().build() - def weakKey = Jwts.SIG.HS256.keyBuilder().build() + def key = alg.key().build() + def weakKey = Jwts.SIG.HS256.key().build() String jws = Jwts.builder().setSubject("Foo").signWith(key, alg).compact() @@ -744,7 +744,7 @@ class JwtsTest { def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ" String jws = withoutSignature + '.' + invalidEncodedSignature - def keypair = Jwts.SIG.ES256.keyPairBuilder().build() + def keypair = Jwts.SIG.ES256.keyPair().build() Jwts.parser().setSigningKey(keypair.public).build().parseClaimsJws(jws) } @@ -754,12 +754,12 @@ class JwtsTest { //create random signing key for testing: def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String notSigned = Jwts.builder().setSubject("Foo").compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(notSigned) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseClaimsJws(notSigned) fail('parseClaimsJws must fail for unsigned JWTs') } catch (UnsupportedJwtException expected) { assertEquals 'Unprotected Claims JWTs are not supported.', expected.message @@ -1025,8 +1025,8 @@ class JwtsTest { def id = realAlg.getId() + 'X' // custom id def alg = new MacAlgorithm() { @Override - SecretKeyBuilder keyBuilder() { - return realAlg.keyBuilder() + SecretKeyBuilder key() { + return realAlg.key() } @Override @@ -1065,7 +1065,7 @@ class JwtsTest { @Test void testParseJweWithCustomEncryptionAlgorithm() { def realAlg = Jwts.ENC.A128GCM // any alg will do, we're going to wrap it - def key = realAlg.keyBuilder().build() + def key = realAlg.key().build() def enc = realAlg.getId() + 'X' // custom id def encAlg = new AeadAlgorithm() { @Override @@ -1084,8 +1084,8 @@ class JwtsTest { } @Override - SecretKeyBuilder keyBuilder() { - return realAlg.keyBuilder() + SecretKeyBuilder key() { + return realAlg.key() } @Override @@ -1135,7 +1135,7 @@ class JwtsTest { try { Jwts.parser() - .setKeyLocator(new ConstantKeyLocator(TestKeys.HS256, TestKeys.A128GCM)) + .keyLocator(new ConstantKeyLocator(TestKeys.HS256, TestKeys.A128GCM)) .addKeyAlgorithms([badKeyAlg]) // <-- add bad alg here .build() .parseClaimsJwe(compact) @@ -1165,7 +1165,7 @@ class JwtsTest { //create random signing key for testing: def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() //this is a 'real', valid JWT: String compact = Jwts.builder().setSubject("Joe").signWith(key, alg).compact() @@ -1178,14 +1178,14 @@ class JwtsTest { String forged = Jwts.builder().setSubject("Not Joe").compact() //assert that our forged header has a 'NONE' algorithm: - assertEquals 'none', Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(forged).getHeader().get('alg') + assertEquals 'none', Jwts.parser().enableUnsecured().build().parseClaimsJwt(forged).getHeader().get('alg') //now let's forge it by appending the signature the server expects: forged += signature //now assert that, when the server tries to parse the forged token, parsing fails: try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parse(forged) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parse(forged) fail("Parsing must fail for a forged token.") } catch (MalformedJwtException expected) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', expected.message @@ -1300,8 +1300,8 @@ class JwtsTest { for (AeadAlgorithm enc : Jwts.ENC.get().values()) { SecretKey key = alg instanceof SecretKeyAlgorithm ? - ((SecretKeyAlgorithm) alg).keyBuilder().build() : - enc.keyBuilder().build() + ((SecretKeyAlgorithm) alg).key().build() : + enc.key().build() // encrypt: String jwe = Jwts.builder() @@ -1328,7 +1328,7 @@ class JwtsTest { for (AeadAlgorithm enc : Jwts.ENC.get().values()) { - SecretKey key = enc.keyBuilder().build() + SecretKey key = enc.key().build() // encrypt and compress: String jwe = Jwts.builder() @@ -1354,7 +1354,7 @@ class JwtsTest { it instanceof Pbes2HsAkwAlgorithm })// as Collection> - Password key = Keys.forPassword("12345678".toCharArray()) + Password key = Keys.password("12345678".toCharArray()) for (KeyAlgorithm alg : algs) { @@ -1379,7 +1379,7 @@ class JwtsTest { @Test void testPasswordJweWithoutSpecifyingAlg() { - Password key = Keys.forPassword("12345678".toCharArray()) + Password key = Keys.password("12345678".toCharArray()) // encrypt: String jwe = Jwts.builder() @@ -1571,7 +1571,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { @@ -1587,11 +1587,11 @@ class JwtsTest { static void testHmac(MacAlgorithm alg) { //create random signing key for testing: - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(key, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(key, alg).compact() def token = Jwts.parser().verifyWith(key).build().parse(jwt) @@ -1607,7 +1607,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy index f4c644258..c73a0eb1d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy @@ -15,6 +15,7 @@ */ package io.jsonwebtoken.impl +import io.jsonwebtoken.Jwts import io.jsonwebtoken.impl.security.Randoms import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.Encoders @@ -56,7 +57,7 @@ class AbstractProtectedHeaderTest { @Test void testJku() { URI uri = URI.create('https://github.com') - def header = h([jku: uri]) + def header = Jwts.header().jwkSetUrl(uri).build() as DefaultProtectedHeader assertEquals uri.toString(), header.get('jku') assertEquals uri, header.getJwkSetUrl() } @@ -108,7 +109,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithJwk() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() EcPublicJwk pubJwk = jwk.toPublicJwk() def header = h([jwk: pubJwk]) assertEquals pubJwk, header.getJwk() @@ -116,7 +117,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithMap() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() EcPublicJwk pubJwk = jwk.toPublicJwk() Map m = new LinkedHashMap<>(pubJwk) def header = h([jwk: m]) @@ -138,7 +139,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithSecretJwk() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() try { h([jwk: jwk]) fail() @@ -151,7 +152,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithPrivateJwk() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() try { h([jwk: jwk]) fail() @@ -212,7 +213,7 @@ class AbstractProtectedHeaderTest { @Test void testCritical() { Set crits = Collections.setOf('foo', 'bar') - def header = h([crit: crits]) + def header = Jwts.header().critical(crits).build() as DefaultProtectedHeader assertEquals crits, header.getCritical() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy index cd4dc5243..ca16d5fdf 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy @@ -57,7 +57,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithSecretJwk() { - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type try { h([epk: values]) @@ -71,7 +71,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithPrivateJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.private as ECPrivateKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.private as ECPrivateKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type try { h([epk: values]) @@ -86,7 +86,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithRsaPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type def epk = h([epk: values]).getEphemeralPublicKey() assertTrue epk instanceof RsaPublicJwk @@ -95,14 +95,14 @@ class DefaultJweHeaderTest { @Test void testEpkWithEcPublicJwkValues() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type assertEquals jwk, h([epk: values]).get('epk') } @Test void testEpkWithInvalidEcPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() def values = new LinkedHashMap(jwk) // copy fields so we can mutate // We have a public JWK for a point on the curve, now swap out the x coordinate for something invalid: values.put('x', 'Kg') @@ -121,7 +121,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithEcPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() header = h([epk: jwk]) assertEquals jwk, header.get('epk') assertEquals jwk, header.getEphemeralPublicKey() @@ -131,7 +131,7 @@ class DefaultJweHeaderTest { void testEpkWithEdPublicJwk() { def keys = TestKeys.EdEC.collect({it -> it.pair.public as PublicKey}) for(PublicKey key : keys) { - def jwk = Jwks.builder().forKey((PublicKey)key as PublicKey).build() + def jwk = Jwks.builder().key((PublicKey)key as PublicKey).build() header = h([epk: jwk]) assertEquals jwk, header.get('epk') assertEquals jwk, header.getEphemeralPublicKey() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy index 67a3f2290..d843995a0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy @@ -28,7 +28,7 @@ class DefaultJweTest { @Test void testToString() { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() def jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact) String encodedIv = Encoders.BASE64URL.encode(jwe.initializationVector) @@ -40,7 +40,7 @@ class DefaultJweTest { @Test void testEqualsAndHashCode() { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() def parser = Jwts.parser().decryptWith(key).build() def jwe1 = parser.parseClaimsJwe(compact) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy index b2393c5f3..179f11d00 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy @@ -36,7 +36,7 @@ class DefaultJwsTest { void testToString() { //create random signing key for testing: def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() int i = compact.lastIndexOf('.') String signature = compact.substring(i + 1) @@ -47,7 +47,7 @@ class DefaultJwsTest { @Test void testEqualsAndHashCode() { def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() def parser = Jwts.parser().verifyWith(key).build() def jws1 = parser.parseClaimsJws(compact) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 850eadb27..de39adb9e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -70,7 +70,7 @@ class DefaultJwtBuilderTest { } @Override - KeyPairBuilder keyPairBuilder() { + KeyPairBuilder keyPair() { throw new IllegalStateException("should not be called during build") } @@ -81,8 +81,8 @@ class DefaultJwtBuilderTest { } replay provider - def b = new DefaultJwtBuilder().setProvider(provider) - .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) + def b = new DefaultJwtBuilder().provider(provider) + .setSubject('me').signWith(Jwts.SIG.HS256.key().build(), alg) assertSame provider, b.provider b.compact() verify provider @@ -113,7 +113,7 @@ class DefaultJwtBuilderTest { } @Override - KeyPairBuilder keyPairBuilder() { + KeyPairBuilder keyPair() { throw new IllegalStateException("should not be called during build") } @@ -123,8 +123,8 @@ class DefaultJwtBuilderTest { } } - def b = new DefaultJwtBuilder().setSecureRandom(random) - .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) + def b = new DefaultJwtBuilder().random(random) + .setSubject('me').signWith(Jwts.SIG.HS256.key().build(), alg) assertSame random, b.secureRandom b.compact() assertTrue called[0] @@ -132,44 +132,53 @@ class DefaultJwtBuilderTest { @Test void testSetHeader() { - def h = Jwts.header().set('foo', 'bar').build() + def h = Jwts.header().add('foo', 'bar').build() builder.setHeader(h) - assertEquals h, builder.buildHeader() + assertEquals h, builder.headerBuilder.build() } @Test void testSetHeaderFromMap() { def m = [foo: 'bar'] builder.setHeader(m) - assertEquals builder.buildHeader().foo, 'bar' + assertEquals builder.headerBuilder.build().foo, 'bar' } @Test void testSetHeaderParams() { def m = [a: 'b', c: 'd'] builder.setHeaderParams(m) - assertEquals builder.buildHeader().a, 'b' - assertEquals builder.buildHeader().c, 'd' + assertEquals builder.headerBuilder.build().a, 'b' + assertEquals builder.headerBuilder.build().c, 'd' } @Test void testSetHeaderParam() { builder.setHeaderParam('foo', 'bar') - assertEquals builder.buildHeader().foo, 'bar' + assertEquals builder.headerBuilder.build().foo, 'bar' } @Test void testSetClaims() { - Claims c = Jwts.claims().set('foo', 'bar').build() + Claims c = Jwts.claims().add('foo', 'bar').build() builder.setClaims(c) assertEquals c, builder.claimsBuilder } + @Test + void testSetClaimsMap() { + def m = [foo: 'bar'] + builder.setClaims(m) + assertEquals 1, builder.claimsBuilder.size() + assertTrue builder.claimsBuilder.containsKey('foo') + assertTrue builder.claimsBuilder.containsValue('bar') + } + @Test void testAddClaims() { def b = new DefaultJwtBuilder() def c = Jwts.claims([initial: 'initial']) - b.setClaims(c) + b.claims().add(c) def c2 = [foo: 'bar', baz: 'buz'] b.addClaims(c2) assertEquals 'initial', b.claimsBuilder.get('initial') @@ -203,8 +212,8 @@ class DefaultJwtBuilderTest { @Test void testExistingClaimsAndSetClaim() { - Claims c = Jwts.claims().set('foo', 'bar').build() - builder.setClaims(c) + Claims c = Jwts.claims().add('foo', 'bar').build() + builder.claims().add(c) assertEquals c, builder.claimsBuilder assertEquals builder.claimsBuilder.size(), 1 assertEquals c.size(), 1 @@ -253,7 +262,7 @@ class DefaultJwtBuilderTest { @Test void testCompactWithJwsHeader() { def b = new DefaultJwtBuilder() - b.header().setKeyId('a') + b.header().keyId('a') b.setPayload('foo') def alg = SignatureAlgorithm.HS256 def key = Keys.secretKeyFor(alg) @@ -273,7 +282,7 @@ class DefaultJwtBuilderTest { throw new SerializationException('foo', new Exception()) } } - def b = new DefaultJwtBuilder().serializeToJsonWith(serializer) + def b = new DefaultJwtBuilder().serializer(serializer) try { b.setPayload('foo').compact() fail() @@ -306,7 +315,7 @@ class DefaultJwtBuilderTest { void testSignWithKeyOnly() { def b = new DefaultJwtBuilder() - b.header().setKeyId('a') + b.header().keyId('a') b.setPayload('foo') def key = KeyGenerator.getInstance('HmacSHA256').generateKey() @@ -417,8 +426,8 @@ class DefaultJwtBuilderTest { return null } } - def b = new DefaultJwtBuilder().base64UrlEncodeWith(encoder) - assertSame encoder, b.base64UrlEncoder + def b = new DefaultJwtBuilder().encoder(encoder) + assertSame encoder, b.encoder } @Test(expected = IllegalArgumentException) @@ -474,7 +483,7 @@ class DefaultJwtBuilderTest { @Test void testCompactSimplestPayload() { def enc = Jwts.ENC.A128GCM - def key = enc.keyBuilder().build() + def key = enc.key().build() def jwe = builder.setPayload("me").encryptWith(key, enc).compact() def jwt = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe) assertEquals 'me', new String(jwt.getPayload(), StandardCharsets.UTF_8) @@ -483,7 +492,7 @@ class DefaultJwtBuilderTest { @Test void testCompactSimplestClaims() { def enc = Jwts.ENC.A128GCM - def key = enc.keyBuilder().build() + def key = enc.key().build() def jwe = builder.setSubject('joe').encryptWith(key, enc).compact() def jwt = Jwts.parser().decryptWith(key).build().parseClaimsJwe(jwe) assertEquals 'joe', jwt.getPayload().getSubject() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy index eafecbe79..430ef5b1f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy @@ -47,7 +47,11 @@ class DefaultJwtHeaderBuilderTest { @SuppressWarnings('GroovyAssignabilityCheck') private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) - builder."set$name"(val) + switch (propName) { + case 'algorithm': builder.add('alg', val); break // no setter + case 'compressionAlgorithm': builder.add('zip', val); break // no setter + default: builder."$propName"(val) + } header = builder.build() if (val instanceof byte[]) { assertArrayEquals val, header."get$name"() @@ -192,7 +196,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testPutAll() { def m = ['foo': 'bar', 'baz': 'bat'] - def header = builder.set(m).build() + def header = builder.add(m).build() assertEquals m, header } @@ -208,7 +212,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testClear() { def m = ['foo': 'bar', 'baz': 'bat'] - builder.set(m) + builder.add(m) builder.clear() def header = builder.build() assertTrue header.isEmpty() @@ -217,7 +221,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testEmpty() { def m = ['foo': 'bar', 'baz': 'bat'] - def header = builder.set(m).empty().build() + def header = builder.add(m).empty().build() assertTrue header.isEmpty() } @@ -259,6 +263,15 @@ class DefaultJwtHeaderBuilderTest { assertSymmetry('compressionAlgorithm', 'DEF') } + @Test + void testDeprecatedSetters() { // TODO: remove before 1.0 + assertEquals 'foo', builder.setType('foo').build().getType() + assertEquals 'foo', builder.setContentType('foo').build().getContentType() + assertEquals 'foo', builder.setCompressionAlgorithm('foo').build().getCompressionAlgorithm() + assertEquals 'foo', builder.setKeyId('foo').build().getKeyId() + assertEquals 'foo', builder.setAlgorithm('foo').build().getAlgorithm() + } + // ====================== Protected Header Methods ======================= /** @@ -277,7 +290,7 @@ class DefaultJwtHeaderBuilderTest { */ @Test void testJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() assertJws('jwk', jwk) } @@ -332,7 +345,7 @@ class DefaultJwtHeaderBuilderTest { def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - builder.setX509CertificateSha1Thumbprint(x5t) + builder.x509CertificateSha1Thumbprint(x5t) header = builder.build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() @@ -345,7 +358,7 @@ class DefaultJwtHeaderBuilderTest { Request request = new DefaultRequest(chain[0].getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - def header = builder.setX509CertificateChain(chain).withX509Sha1Thumbprint(true).build() as JwsHeader + def header = builder.x509CertificateChain(chain).withX509Sha1Thumbprint(true).build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() assertEquals encoded, header.get('x5t') @@ -361,7 +374,7 @@ class DefaultJwtHeaderBuilderTest { def x5tS256 = Jwks.HASH.@SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - builder.setX509CertificateSha256Thumbprint(x5tS256) + builder.x509CertificateSha256Thumbprint(x5tS256) header = builder.build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() @@ -374,7 +387,7 @@ class DefaultJwtHeaderBuilderTest { Request request = new DefaultRequest(chain[0].getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - def header = builder.setX509CertificateChain(chain).withX509Sha256Thumbprint(true).build() as JwsHeader + def header = builder.x509CertificateChain(chain).withX509Sha256Thumbprint(true).build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() assertEquals encoded, header.get('x5t#S256') @@ -393,7 +406,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testEphemeralPublicKey() { def key = TestKeys.ES256.pair.public - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() builder.put('epk', jwk) header = builder.build() as JweHeader assertEquals jwk, header.getEphemeralPublicKey() @@ -409,7 +422,7 @@ class DefaultJwtHeaderBuilderTest { void testAgreementPartyUInfoString() { def s = "UInfo" def info = Strings.utf8(s) - builder.setAgreementPartyUInfo(s).build() + builder.agreementPartyUInfo(s).build() header = builder.build() as JweHeader assertArrayEquals info, header.getAgreementPartyUInfo() } @@ -424,7 +437,7 @@ class DefaultJwtHeaderBuilderTest { void testAgreementPartyVInfoString() { def s = "VInfo" def info = Strings.utf8(s) - builder.setAgreementPartyVInfo(s) + builder.agreementPartyVInfo(s) header = builder.build() as JweHeader assertArrayEquals info, header.getAgreementPartyVInfo() } @@ -465,7 +478,7 @@ class DefaultJwtHeaderBuilderTest { assertEquals new DefaultHeader([foo: 'bar']), builder.build() // add JWS-required property: - builder.setAlgorithm('HS256') + builder.put(DefaultHeader.ALGORITHM.getId(), 'HS256') assertEquals new DefaultJwsHeader([foo: 'bar', alg: 'HS256']), builder.build() // add JWE required property: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index eb217265c..100564620 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -24,10 +24,12 @@ import io.jsonwebtoken.io.Decoder import io.jsonwebtoken.io.DecodingException import io.jsonwebtoken.io.DeserializationException import io.jsonwebtoken.io.Deserializer +import io.jsonwebtoken.security.* import org.hamcrest.CoreMatchers import org.junit.Before import org.junit.Test +import javax.crypto.SecretKey import java.security.Provider import static org.easymock.EasyMock.* @@ -53,7 +55,7 @@ class DefaultJwtParserBuilderTest { Provider provider = createMock(Provider) replay provider - def parser = builder.setProvider(provider).build() + def parser = builder.provider(provider).build() assertSame provider, parser.provider verify provider @@ -63,7 +65,7 @@ class DefaultJwtParserBuilderTest { void testKeyLocatorAndVerificationKeyConfigured() { try { builder - .setKeyLocator(new ConstantKeyLocator(null, null)) + .keyLocator(new ConstantKeyLocator(null, null)) .verifyWith(TestKeys.HS256) .build() fail() @@ -77,7 +79,7 @@ class DefaultJwtParserBuilderTest { void testKeyLocatorAndDecryptionKeyConfigured() { try { builder - .setKeyLocator(new ConstantKeyLocator(null, null)) + .keyLocator(new ConstantKeyLocator(null, null)) .decryptWith(TestKeys.A128GCM) .build() fail() @@ -101,7 +103,7 @@ class DefaultJwtParserBuilderTest { } } def b = builder.base64UrlDecodeWith(decoder).build() - assertSame decoder, b.base64UrlDecoder + assertSame decoder, b.decoder } @Test(expected = IllegalArgumentException) @@ -121,7 +123,7 @@ class DefaultJwtParserBuilderTest { assertSame deserializer, p.deserializer def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String jws = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() @@ -161,10 +163,122 @@ class DefaultJwtParserBuilderTest { void testAddCompressionAlgorithms() { def codec = new TestCompressionCodec(id: 'test') def parser = builder.addCompressionAlgorithms([codec] as Set).build() - def header = Jwts.header().setCompressionAlgorithm(codec.getId()).build() + def header = Jwts.header().add('zip', codec.getId()).build() assertSame codec, parser.zipAlgFn.locate(header) } + @Test + void testAddCompressionAlgorithmsOverrideDefaults() { + def header = Jwts.header().add('zip', 'DEF').build() + def parser = builder.build() + assertSame Jwts.ZIP.DEF, parser.zipAlgFn.apply(header) // standard implementation default + + def alg = new TestCompressionCodec(id: 'DEF') // custom impl with standard identifier + parser = builder.addCompressionAlgorithms([alg]).build() + assertSame alg, parser.zipAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveCompressionAlgorithm() { + def standard = Jwts.header().add('zip', 'DEF').build() + def nonStandard = Jwts.header().add('zip', 'def').build() + def parser = builder.build() + assertSame Jwts.ZIP.DEF, parser.zipAlgFn.apply(standard) // standard implementation default + try { + parser.zipAlgFn.apply(nonStandard) + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWT ${DefaultHeader.COMPRESSION_ALGORITHM} header value: def" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddEncryptionAlgorithmsOverrideDefaults() { + final String standardId = Jwts.ENC.A256GCM.getId() + def header = Jwts.header().add('enc', standardId).build() + def parser = builder.build() + assertSame Jwts.ENC.A256GCM, parser.encAlgFn.apply(header) // standard implementation default + + def custom = new TestAeadAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addEncryptionAlgorithms([custom]).build() + assertSame custom, parser.encAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveEncryptionAlgorithm() { + def alg = Jwts.ENC.A256GCM + def standard = Jwts.header().add('enc', alg.id).build() + def nonStandard = Jwts.header().add('enc', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.encAlgFn.apply(standard) // standard id + try { + parser.encAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWE ${DefaultJweHeader.ENCRYPTION_ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddKeyAlgorithmsOverrideDefaults() { + final String standardId = Jwts.KEY.A256GCMKW.id + def header = Jwts.header().add('enc', Jwts.ENC.A256GCM.id).add('alg', standardId).build() + def parser = builder.build() + assertSame Jwts.KEY.A256GCMKW, parser.keyAlgFn.apply(header) // standard implementation default + + def custom = new TestKeyAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addKeyAlgorithms([custom]).build() + assertSame custom, parser.keyAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveKeyAlgorithm() { + def alg = Jwts.KEY.A256GCMKW + def hb = Jwts.header().add('enc', Jwts.ENC.A256GCM.id) + def standard = hb.add('alg', alg.id).build() + def nonStandard = hb.add('alg', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.keyAlgFn.apply(standard) // standard id + try { + parser.keyAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWE ${DefaultJweHeader.ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddSignatureAlgorithmsOverrideDefaults() { + final String standardId = Jwts.SIG.HS256.id + def header = Jwts.header().add('alg', standardId).build() + def parser = builder.build() + assertSame Jwts.SIG.HS256, parser.sigAlgFn.apply(header) // standard implementation default + + def custom = new TestMacAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addSignatureAlgorithms([custom]).build() + assertSame custom, parser.sigAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveSignatureAlgorithm() { + def alg = Jwts.SIG.HS256 + def hb = Jwts.header().add('alg', alg.id) + def standard = hb.build() + def nonStandard = hb.add('alg', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.sigAlgFn.apply(standard) // standard id + try { + parser.sigAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWS ${DefaultJwsHeader.ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + @Test void testCompressionCodecResolverAndExtraCompressionCodecs() { def codec = new TestCompressionCodec(id: 'test') @@ -189,7 +303,7 @@ class DefaultJwtParserBuilderTest { builder.enableUnsecuredDecompression().build() fail() } catch (IllegalStateException ise) { - String expected = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecuredJws' " + "is also configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications." + String expected = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecured' " + "is also configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications." assertEquals expected, ise.getMessage() } } @@ -199,7 +313,7 @@ class DefaultJwtParserBuilderTest { def codec = Jwts.ZIP.GZIP String jwt = Jwts.builder().compressWith(codec).setSubject('joe').compact() try { - builder.enableUnsecuredJws().build().parse(jwt) + builder.enableUnsecured().build().parse(jwt) fail() } catch (UnsupportedJwtException e) { String expected = String.format(DefaultJwtParser.UNPROTECTED_DECOMPRESSION_MSG, codec.getId()) @@ -211,7 +325,7 @@ class DefaultJwtParserBuilderTest { void testDecompressUnprotectedJwtEnabled() { def codec = Jwts.ZIP.GZIP String jws = Jwts.builder().compressWith(codec).setSubject('joe').compact() - def jwt = builder.enableUnsecuredJws().enableUnsecuredDecompression().build().parse(jws) + def jwt = builder.enableUnsecured().enableUnsecuredDecompression().build().parse(jws) assertEquals 'joe', ((Claims) jwt.getPayload()).getSubject() } @@ -252,6 +366,11 @@ class DefaultJwtParserBuilderTest { return this.id } + @Override + String getId() { + return this.id + } + @Override byte[] compress(byte[] content) throws CompressionException { return new byte[0] @@ -261,10 +380,87 @@ class DefaultJwtParserBuilderTest { byte[] decompress(byte[] compressed) throws CompressionException { return new byte[0] } + } + + static class TestAeadAlgorithm implements AeadAlgorithm { + + String id + int keyBitLength = 256 + + @Override + String getId() { + return id + } + + @Override + AeadResult encrypt(AeadRequest request) throws SecurityException { + return null + } + + @Override + Message decrypt(DecryptAeadRequest request) throws SecurityException { + return null + } + + @Override + SecretKeyBuilder key() { + return null + } + + @Override + int getKeyBitLength() { + return keyBitLength + } + } + + static class TestKeyAlgorithm implements KeyAlgorithm { + + String id + int keyBitLength = 256 @Override String getId() { - return this.id + return id + } + + @Override + KeyResult getEncryptionKey(KeyRequest request) throws SecurityException { + return null + } + + @Override + SecretKey getDecryptionKey(DecryptionKeyRequest request) throws SecurityException { + return null + } + } + + static class TestMacAlgorithm implements MacAlgorithm { + + String id + + @Override + String getId() { + return id + } + + @Override + byte[] digest(SecureRequest request) throws SecurityException { + return new byte[0] + } + + @Override + boolean verify(VerifySecureDigestRequest request) throws SecurityException { + return false + } + + @Override + SecretKeyBuilder key() { + return null + } + + @Override + int getKeyBitLength() { + return 0 } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy index 2ed6cdb80..074eee389 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy @@ -50,7 +50,7 @@ class DefaultJwtParserTest { @Test(expected = MalformedJwtException) void testBase64UrlDecodeWithInvalidInput() { - newParser().base64UrlDecode('20:SLDKJF;3993;----', 'test') + newParser().decode('20:SLDKJF;3993;----', 'test') } @Test @@ -66,7 +66,7 @@ class DefaultJwtParserTest { assertTrue("Expected wrapping deserializer to be instance of JwtDeserializer", p.deserializer instanceof JwtDeserializer ) assertSame deserializer, p.deserializer.deserializer - def key = Jwts.SIG.HS256.keyBuilder().build() + def key = Jwts.SIG.HS256.key().build() String jws = Jwts.builder().claim('foo', 'bar').signWith(key, Jwts.SIG.HS256).compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy index 69c06b638..89927a0e2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy @@ -29,8 +29,8 @@ class DefaultJwtTest { @Test void testToString() { - String compact = Jwts.builder().setHeaderParam('foo', 'bar').setAudience('jsmith').compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + String compact = Jwts.builder().header().add('foo', 'bar').and().audience('jsmith').compact() + Jwt jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals 'header={foo=bar, alg=none},payload={aud=jsmith}', jwt.toString() } @@ -38,15 +38,15 @@ class DefaultJwtTest { void testByteArrayPayloadToString() { byte[] bytes = 'hello JJWT'.getBytes(StandardCharsets.UTF_8) String encoded = Encoders.BASE64URL.encode(bytes) - String compact = Jwts.builder().setHeaderParam('foo', 'bar').setContent(bytes).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + String compact = Jwts.builder().header().add('foo', 'bar').and().content(bytes).compact() + Jwt jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals "header={foo=bar, alg=none},payload=$encoded" as String, jwt.toString() } @Test void testEqualsAndHashCode() { String compact = Jwts.builder().claim('foo', 'bar').compact() - def parser = Jwts.parser().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecured().build() def jwt1 = parser.parseClaimsJwt(compact) def jwt2 = parser.parseClaimsJwt(compact) assertNotEquals jwt1, 'hello' as String @@ -60,7 +60,7 @@ class DefaultJwtTest { @Test void testBodyAndPayloadSame() { String compact = Jwts.builder().claim('foo', 'bar').compact() - def parser = Jwts.parser().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecured().build() def jwt1 = parser.parseClaimsJwt(compact) def jwt2 = parser.parseClaimsJwt(compact) assertEquals jwt1.getBody(), jwt1.getPayload() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy index 9a74abf3b..3961f4564 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy @@ -43,7 +43,11 @@ class DefaultMutableJweHeaderTest { @SuppressWarnings('GroovyAssignabilityCheck') private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) - header."set$name"(val) + switch (propName) { + case 'algorithm': header.add('alg', val); break // no setter + case 'compressionAlgorithm': header.add('zip', val); break // no setter + default: header."$propName"(val) + } if (val instanceof byte[]) { assertArrayEquals val, header."get$name"() @@ -214,7 +218,7 @@ class DefaultMutableJweHeaderTest { */ @Test void testJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() assertSymmetry('jwk', jwk) } @@ -269,7 +273,7 @@ class DefaultMutableJweHeaderTest { def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - header.setX509CertificateSha1Thumbprint(x5t) + header.x509CertificateSha1Thumbprint(x5t) assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() assertEquals encoded, header.get('x5t') } @@ -284,7 +288,7 @@ class DefaultMutableJweHeaderTest { def x5tS256 = Jwks.HASH.@SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - header.setX509CertificateSha256Thumbprint(x5tS256) + header.x509CertificateSha256Thumbprint(x5tS256) assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() assertEquals encoded, header.get('x5t#S256') } @@ -301,7 +305,7 @@ class DefaultMutableJweHeaderTest { @Test void testEphemeralPublicKey() { def key = TestKeys.ES256.pair.public - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() header.put('epk', jwk) assertEquals jwk, header.getEphemeralPublicKey() } @@ -316,7 +320,7 @@ class DefaultMutableJweHeaderTest { void testAgreementPartyUInfoString() { def s = "UInfo" def info = Strings.utf8(s) - header.setAgreementPartyVInfo(s) + header.agreementPartyVInfo(s) assertArrayEquals info, header.getAgreementPartyVInfo() } @@ -330,7 +334,7 @@ class DefaultMutableJweHeaderTest { void testAgreementPartyVInfoString() { def s = "VInfo" def info = Strings.utf8(s) - header.setAgreementPartyVInfo(s) + header.agreementPartyVInfo(s) assertArrayEquals info, header.getAgreementPartyVInfo() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy deleted file mode 100644 index 95ff6211e..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2015 jsonwebtoken.io - * - * 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 io.jsonwebtoken.impl - -import org.junit.Test -import org.junit.runner.RunWith -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner - -import static org.junit.Assert.* - -@RunWith(PowerMockRunner.class) -@PrepareForTest([System.class]) -class DefaultTextCodecFactoryTest { - - @Test - void testGetSystemProperty() { - def factory = new DefaultTextCodecFactory() - assertNotNull factory.getSystemProperty("java.version") - } - - @Test - void testIsAndroidByVmName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - return 'dalvik' - } - } - - assertTrue factory.getTextCodec() instanceof AndroidBase64Codec - } - - @Test - void testIsAndroidByNullVmName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - if (key == 'java.vm.name') return null; - return 'android' - } - } - - assertTrue factory.getTextCodec() instanceof AndroidBase64Codec - } - - @Test - void testIsAndroidByNullVmNameAndNullVendorName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - return null - } - } - - assertFalse factory.getTextCodec() instanceof AndroidBase64Codec - } -} diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy index d7acb07dd..0e5f52419 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy @@ -46,7 +46,7 @@ class IdLocatorTest { @Test void unrequiredHeaderValueTest() { locator = new IdLocator(TEST_FIELD, registry, Collections.emptyList(), null) - def header = Jwts.header().setAlgorithm('none').build() + def header = Jwts.header().add('a', 'b').build() assertNull locator.apply(header) } @@ -63,7 +63,7 @@ class IdLocatorTest { @Test void unlocatableJwtHeaderInstanceTest() { - def header = Jwts.header().set('foo', 'foo').build() + def header = Jwts.header().add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { @@ -74,7 +74,7 @@ class IdLocatorTest { @Test void unlocatableJwsHeaderInstanceTest() { - def header = Jwts.header().setAlgorithm('HS256').set('foo', 'foo').build() + def header = Jwts.header().add('alg', 'HS256').add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { @@ -85,7 +85,7 @@ class IdLocatorTest { @Test void unlocatableJweHeaderInstanceTest() { - def header = Jwts.header().set('enc', 'A256GCM').set('foo', 'foo').build() + def header = Jwts.header().add('enc', 'A256GCM').add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy index 743071eff..1fec882b1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy @@ -65,7 +65,7 @@ class JwtTokenizerTest { assertEquals 'header', tjwe.getProtected() assertEquals 'encryptedKey', tjwe.getEncryptedKey() assertEquals 'initializationVector', tjwe.getIv() - assertEquals 'body', tjwe.getBody() + assertEquals 'body', tjwe.getPayload() assertEquals 'authenticationTag', tjwe.getDigest() } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy index 184466ae9..5850a98fb 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy @@ -33,7 +33,7 @@ class DeflateCompressionCodecTest { @Test void testBackwardsCompatibility_0_10_6() { final String jwtFrom0106 = 'eyJhbGciOiJub25lIiwiemlwIjoiREVGIn0.eNqqVsosLlayUspNVdJRKi5NAjJLi1OLgJzMxBIlK0sTMzMLEwsDAx2l1IoCJSsTQwMjExOQQC0AAAD__w.' - Jwts.parser().enableUnsecuredJws().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown + Jwts.parser().enableUnsecured().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown } /** diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy index d24776a02..c3d3384ad 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy @@ -34,19 +34,19 @@ class AbstractAsymmetricJwkBuilderTest { private static final RSAPublicKey PUB_KEY = CERT.getPublicKey() as RSAPublicKey private static RsaPublicJwkBuilder builder() { - return Jwks.builder().forKey(PUB_KEY) + return Jwks.builder().key(PUB_KEY) } @Test void testUse() { def val = UUID.randomUUID().toString() - def jwk = builder().setPublicKeyUse(val).build() + def jwk = builder().publicKeyUse(val).build() assertEquals val, jwk.getPublicKeyUse() assertEquals val, jwk.use RSAPrivateKey privateKey = TestKeys.RS256.pair.private as RSAPrivateKey - jwk = builder().setPublicKeyUse(val).setPrivateKey(privateKey).build() + jwk = builder().publicKeyUse(val).privateKey(privateKey).build() assertEquals val, jwk.getPublicKeyUse() assertEquals val, jwk.use } @@ -54,12 +54,12 @@ class AbstractAsymmetricJwkBuilderTest { @Test void testX509Url() { def val = new URI(UUID.randomUUID().toString()) - assertSame val, builder().setX509Url(val).build().getX509Url() + assertSame val, builder().x509Url(val).build().getX509Url() } @Test void testX509CertificateChain() { - assertEquals CHAIN, builder().setX509CertificateChain(CHAIN).build().getX509CertificateChain() + assertEquals CHAIN, builder().x509CertificateChain(CHAIN).build().getX509CertificateChain() } @Test @@ -67,7 +67,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) def encoded = Encoders.BASE64URL.encode(x5t) - def jwk = builder().setX509CertificateSha1Thumbprint(x5t).build() + def jwk = builder().x509CertificateSha1Thumbprint(x5t).build() assertArrayEquals x5t, jwk.getX509CertificateSha1Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T.getId()) } @@ -77,7 +77,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) def encoded = Encoders.BASE64URL.encode(x5t) - def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha1Thumbprint(true).build() + def jwk = builder().x509CertificateChain(CHAIN).withX509Sha1Thumbprint(true).build() assertArrayEquals x5t, jwk.getX509CertificateSha1Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T.getId()) } @@ -87,7 +87,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) def encoded = Encoders.BASE64URL.encode(x5tS256) - def jwk = builder().setX509CertificateSha256Thumbprint(x5tS256).build() + def jwk = builder().x509CertificateSha256Thumbprint(x5tS256).build() assertArrayEquals x5tS256, jwk.getX509CertificateSha256Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T_S256.getId()) } @@ -97,7 +97,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) def encoded = Encoders.BASE64URL.encode(x5tS256) - def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha256Thumbprint(true).build() + def jwk = builder().x509CertificateChain(CHAIN).withX509Sha256Thumbprint(true).build() assertArrayEquals x5tS256, jwk.getX509CertificateSha256Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T_S256.getId()) } @@ -107,11 +107,11 @@ class AbstractAsymmetricJwkBuilderTest { def pair = TestKeys.ES256.pair //start with a public key builder - def builder = Jwks.builder().forKey(pair.public as ECPublicKey) + def builder = Jwks.builder().key(pair.public as ECPublicKey) assertTrue builder instanceof AbstractAsymmetricJwkBuilder.DefaultEcPublicJwkBuilder //applying the private key turns it into a private key builder - builder = builder.setPrivateKey(pair.private as ECPrivateKey) + builder = builder.privateKey(pair.private as ECPrivateKey) assertTrue builder instanceof AbstractAsymmetricJwkBuilder.DefaultEcPrivateJwkBuilder //building creates a private jwk: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy index 835fffd6f..46a1833a6 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy @@ -83,7 +83,7 @@ class AbstractEcJwkFactoryTest { @Test void testAddSamePointDoublesIt() { - def pair = Jwts.SIG.ES256.keyPairBuilder().build() + def pair = Jwts.SIG.ES256.keyPair().build() def pub = pair.getPublic() as ECPublicKey def spec = pub.getParams() @@ -98,7 +98,7 @@ class AbstractEcJwkFactoryTest { @Test void testDerivePublicFails() { - def pair = Jwts.SIG.ES256.keyPairBuilder().build() + def pair = Jwts.SIG.ES256.keyPair().build() def priv = pair.getPrivate() as ECPrivateKey final def context = new DefaultJwkContext(DefaultEcPrivateJwk.FIELDS) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy index 5696949d2..c0e41b3bc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy @@ -32,7 +32,7 @@ class AbstractJwkBuilderTest { private static final SecretKey SKEY = TestKeys.A256GCM private static AbstractJwkBuilder builder() { - return (AbstractJwkBuilder) Jwks.builder().forKey(SKEY) + return (AbstractJwkBuilder) Jwks.builder().key(SKEY) } @Test @@ -55,20 +55,20 @@ class AbstractJwkBuilderTest { def foo = UUID.randomUUID() def bar = UUID.randomUUID().toString() //different type def m = [foo: foo, bar: bar] - def jwk = builder().set(m).build() + def jwk = builder().add(m).build() assertEquals foo, jwk.foo assertEquals bar, jwk.bar } @Test void testRemove() { - def jwk = builder().set('foo', 'bar').delete('foo').build() as Jwk + def jwk = builder().add('foo', 'bar').delete('foo').build() as Jwk assertNull jwk.get('foo') } @Test void testClear() { - def builder = builder().set('foo', 'bar') + def builder = builder().add('foo', 'bar') builder.clear() def jwk = builder.build() assertNull jwk.get('foo') @@ -76,14 +76,14 @@ class AbstractJwkBuilderTest { @Test void testEmpty() { - def jwk = builder().set('foo', 'bar').empty().build() as Jwk + def jwk = builder().add('foo', 'bar').empty().build() as Jwk assertNull jwk.get('foo') } @Test void testAlgorithm() { def alg = 'someAlgorithm' - def jwk = builder().setAlgorithm(alg).build() + def jwk = builder().algorithm(alg).build() assertEquals alg, jwk.getAlgorithm() assertEquals alg, jwk.alg //test raw get via JWA member id } @@ -91,7 +91,7 @@ class AbstractJwkBuilderTest { @Test void testAlgorithmByPut() { def alg = 'someAlgorithm' - def jwk = builder().set('alg', alg).build() //ensure direct put still is handled properly + def jwk = builder().add('alg', alg).build() //ensure direct put still is handled properly assertEquals alg, jwk.getAlgorithm() assertEquals alg, jwk.alg //test raw get via JWA member id } @@ -99,7 +99,7 @@ class AbstractJwkBuilderTest { @Test void testId() { def kid = UUID.randomUUID().toString() - def jwk = builder().setId(kid).build() + def jwk = builder().id(kid).build() assertEquals kid, jwk.getId() assertEquals kid, jwk.kid //test raw get via JWA member id } @@ -107,7 +107,7 @@ class AbstractJwkBuilderTest { @Test void testIdByPut() { def kid = UUID.randomUUID().toString() - def jwk = builder().set('kid', kid).build() + def jwk = builder().add('kid', kid).build() assertEquals kid, jwk.getId() assertEquals kid, jwk.kid //test raw get via JWA member id } @@ -117,7 +117,7 @@ class AbstractJwkBuilderTest { def a = UUID.randomUUID().toString() def b = UUID.randomUUID().toString() def set = [a, b] as Set - def jwk = builder().setOperations(set).build() + def jwk = builder().operations(set).build() assertEquals set, jwk.getOperations() assertEquals set, jwk.key_ops } @@ -127,7 +127,7 @@ class AbstractJwkBuilderTest { def a = UUID.randomUUID().toString() def b = UUID.randomUUID().toString() def set = [a, b] as Set - def jwk = builder().set('key_ops', set).build() + def jwk = builder().add('key_ops', set).build() assertEquals set, jwk.getOperations() assertEquals set, jwk.key_ops } @@ -137,7 +137,7 @@ class AbstractJwkBuilderTest { void testOperationsByPutSingleValue() { def a = UUID.randomUUID().toString() def set = [a] as Set - def jwk = builder().set('key_ops', a).build() // <-- put uses single raw value, not a set + def jwk = builder().add('key_ops', a).build() // <-- put uses single raw value, not a set assertEquals set, jwk.getOperations() // <-- still get a set assertEquals set, jwk.key_ops // <-- still get a set } @@ -145,7 +145,7 @@ class AbstractJwkBuilderTest { @Test void testProvider() { def provider = Providers.findBouncyCastle(Conditions.TRUE) - def jwk = builder().setProvider(provider).build() + def jwk = builder().provider(provider).build() assertEquals 'oct', jwk.getType() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy index 126609930..88a3b7ba6 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy @@ -131,13 +131,13 @@ class AbstractJwkTest { @Test void testPrivateJwkToStringHasRedactedValues() { - def secretJwk = Jwks.builder().forKey(TestKeys.HS256).build() + def secretJwk = Jwks.builder().key(TestKeys.HS256).build() assertTrue secretJwk.toString().contains('k=') - def ecPrivJwk = Jwks.builder().forKey(TestKeys.ES256.pair.private).build() + def ecPrivJwk = Jwks.builder().key(TestKeys.ES256.pair.private).build() assertTrue ecPrivJwk.toString().contains('d=') - def rsaPrivJwk = Jwks.builder().forKey(TestKeys.RS256.pair.private).build() + def rsaPrivJwk = Jwks.builder().key(TestKeys.RS256.pair.private).build() String s = 'd=, p=, q=, dp=, dq=, qi=' assertTrue rsaPrivJwk.toString().contains(s) } @@ -146,20 +146,20 @@ class AbstractJwkTest { void testPrivateJwkHashCode() { assertEquals jwk.hashCode(), jwk.@context.hashCode() - def secretJwk1 = Jwks.builder().forKey(TestKeys.HS256).set('hello', 'world').build() - def secretJwk2 = Jwks.builder().forKey(TestKeys.HS256).set('hello', 'world').build() + def secretJwk1 = Jwks.builder().key(TestKeys.HS256).add('hello', 'world').build() + def secretJwk2 = Jwks.builder().key(TestKeys.HS256).add('hello', 'world').build() assertEquals secretJwk1.hashCode(), secretJwk1.@context.hashCode() assertEquals secretJwk2.hashCode(), secretJwk2.@context.hashCode() assertEquals secretJwk1.hashCode(), secretJwk2.hashCode() - def ecPrivJwk1 = Jwks.builder().forKey(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() - def ecPrivJwk2 = Jwks.builder().forKey(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() + def ecPrivJwk1 = Jwks.builder().key(TestKeys.ES256.pair.private).add('hello', 'ecworld').build() + def ecPrivJwk2 = Jwks.builder().key(TestKeys.ES256.pair.private).add('hello', 'ecworld').build() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk2.hashCode() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk1.@context.hashCode() assertEquals ecPrivJwk2.hashCode(), ecPrivJwk2.@context.hashCode() - def rsaPrivJwk1 = Jwks.builder().forKey(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() - def rsaPrivJwk2 = Jwks.builder().forKey(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() + def rsaPrivJwk1 = Jwks.builder().key(TestKeys.RS256.pair.private).add('hello', 'rsaworld').build() + def rsaPrivJwk2 = Jwks.builder().key(TestKeys.RS256.pair.private).add('hello', 'rsaworld').build() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk2.hashCode() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk1.@context.hashCode() assertEquals rsaPrivJwk2.hashCode(), rsaPrivJwk2.@context.hashCode() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy index 4fd0b19df..288297779 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy @@ -32,7 +32,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testSignAndVerifyWithExplicitProvider() { Provider provider = Security.getProvider('BC') - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() byte[] data = 'foo'.getBytes(StandardCharsets.UTF_8) byte[] signature = Jwts.SIG.RS256.digest(new DefaultSecureRequest(data, provider, null, pair.getPrivate())) assertTrue Jwts.SIG.RS256.verify(new DefaultVerifySecureDigestRequest(data, provider, null, pair.getPublic(), signature)) @@ -40,7 +40,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testSignFailsWithAnExternalException() { - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() def ise = new IllegalStateException('foo') def alg = new TestAbstractSecureDigestAlgorithm() { @Override @@ -59,7 +59,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testVerifyFailsWithExternalException() { - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() def ise = new IllegalStateException('foo') def alg = new TestAbstractSecureDigestAlgorithm() { @Override diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy index 831dddbef..5795a689f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy @@ -108,7 +108,7 @@ class AesAlgorithmTest { def secureRandom = new SecureRandom() - def req = new DefaultAeadRequest('data'.getBytes(), null, secureRandom, alg.keyBuilder().build(), 'aad'.getBytes()) + def req = new DefaultAeadRequest('data'.getBytes(), null, secureRandom, alg.key().build(), 'aad'.getBytes()) def returnedSecureRandom = alg.ensureSecureRandom(req) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy index d986a049c..2091fc5da 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy @@ -49,8 +49,8 @@ class AesGcmKeyAlgorithmTest { def iv = new byte[12] Randoms.secureRandom().nextBytes(iv) - def kek = alg.keyBuilder().build() - def cek = alg.keyBuilder().build() + def kek = alg.key().build() + def cek = alg.key().build() final String jcaName = "AES/GCM/NoPadding" @@ -102,7 +102,7 @@ class AesGcmKeyAlgorithmTest { def cek = template.generateSecretKey(keyLength) def enc = new GcmAesAeadAlgorithm(keyLength) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(cek) } } @@ -140,7 +140,7 @@ class AesGcmKeyAlgorithmTest { def cek = template.generateSecretKey(keyLength) def enc = new GcmAesAeadAlgorithm(keyLength) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(cek) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy index 77538b909..76b1a8e79 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy @@ -51,7 +51,7 @@ class CurvesTest { @Test void testKeyPairBuilders() { Curves.VALUES.each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() if (it instanceof ECCurve) { assertEquals ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, pair.getPublic().getAlgorithm() assertEquals ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, pair.getPrivate().getAlgorithm() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy index f72f877b8..9bf02e14a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy @@ -78,7 +78,7 @@ class DefaultCurveTest { @Test void testKeyPairBuilder() { - def builder = curve.keyPairBuilder() + def builder = curve.keyPair() assertEquals 'bar', builder.jcaName //builder is an instanceof DefaultKeyPairBuilder } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy index 6f62aaa76..f77993071 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy @@ -28,7 +28,7 @@ class DefaultJwkContextTest { void testX509Url() { def uri = URI.create('https://github.com/jwtk/jjwt') def ctx = new DefaultJwkContext() - ctx.setX509Url(uri) + ctx.x509Url(uri) assertEquals uri, ctx.getX509Url() assertEquals uri.toString(), ctx.get('x5u') } @@ -37,7 +37,7 @@ class DefaultJwkContextTest { void testX509CertificateChain() { def chain = TestKeys.RS256.chain def ctx = new DefaultJwkContext() - ctx.setX509CertificateChain(chain) + ctx.x509CertificateChain(chain) assertEquals chain, ctx.getX509CertificateChain() } @@ -45,7 +45,7 @@ class DefaultJwkContextTest { void testX509CertificateSha1Thumbprint() { def thumbprint = Bytes.randomBits(128) def ctx = new DefaultJwkContext() - ctx.setX509CertificateSha1Thumbprint(thumbprint) + ctx.x509CertificateSha1Thumbprint(thumbprint) assertArrayEquals thumbprint, ctx.getX509CertificateSha1Thumbprint() assertEquals Encoders.BASE64URL.encode(thumbprint), ctx.get('x5t') } @@ -54,7 +54,7 @@ class DefaultJwkContextTest { void testX509CertificateSha256Thumbprint() { def thumbprint = Bytes.randomBits(256) def ctx = new DefaultJwkContext() - ctx.setX509CertificateSha256Thumbprint(thumbprint) + ctx.x509CertificateSha256Thumbprint(thumbprint) assertArrayEquals thumbprint, ctx.getX509CertificateSha256Thumbprint() assertEquals Encoders.BASE64URL.encode(thumbprint), ctx.get('x5t#S256') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy index 5608ed15c..195f5f512 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy @@ -40,7 +40,7 @@ class DefaultJwkParserBuilderTest { @Test void testProvider() { def provider = createMock(Provider) - def parser = Jwks.parser().setProvider(provider).build() as DefaultJwkParser + def parser = Jwks.parser().provider(provider).build() as DefaultJwkParser assertSame provider, parser.provider } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy index 43355c5d1..5543528ef 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy @@ -48,7 +48,7 @@ class DefaultJwkParserTest { def serializer = Services.loadFirst(Serializer) for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) def parsed = Jwks.parser().build().parse(json) @@ -75,10 +75,10 @@ class DefaultJwkParserTest { for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) - def parsed = Jwks.parser().setProvider(provider).build().parse(json) + def parsed = Jwks.parser().provider(provider).build().parse(json) assertEquals jwk, parsed assertSame provider, parsed.@context.@provider } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy index 2c27bd0e3..b2ace2f1c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy @@ -42,7 +42,7 @@ class DefaultMacAlgorithmTest { */ @Test void testWithPasswordSpec() { - def password = Keys.forPassword(passwordChars) + def password = Keys.password(passwordChars) try { newAlg().digest(request(password)) } catch (InvalidKeyException expected) { @@ -98,16 +98,16 @@ class DefaultMacAlgorithmTest { @Test(expected = SecurityException) void testKeyGeneratorNoSuchAlgorithm() { DefaultMacAlgorithm alg = new DefaultMacAlgorithm('HS256', 'foo', 256) - alg.keyBuilder().build() + alg.key().build() } @Test void testKeyGeneratorKeyLength() { DefaultMacAlgorithm alg = new DefaultMacAlgorithm('HS256', 'HmacSHA256', 256) - assertEquals 256, alg.keyBuilder().build().getEncoded().length * Byte.SIZE + assertEquals 256, alg.key().build().getEncoded().length * Byte.SIZE alg = new DefaultMacAlgorithm('A128CBC-HS256', 'HmacSHA256', 128) - assertEquals 128, alg.keyBuilder().build().getEncoded().length * Byte.SIZE + assertEquals 128, alg.key().build().getEncoded().length * Byte.SIZE } @Test(expected = IllegalArgumentException) @@ -146,7 +146,7 @@ class DefaultMacAlgorithmTest { String msg = 'The signing key\'s size is 192 bits which is not secure enough for the HS256 algorithm. ' + 'The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HS256 MUST have a ' + 'size >= 256 bits (the key size must be greater than or equal to the hash output size). ' + - 'Consider using the Jwts.SIG.HS256.keyBuilder() method to create a key guaranteed ' + + 'Consider using the Jwts.SIG.HS256.key() builder to create a key guaranteed ' + 'to be secure enough for HS256. See https://tools.ietf.org/html/rfc7518#section-3.2 for more ' + 'information.' assertEquals msg, expected.getMessage() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy index 103671e0a..e243887b4 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy @@ -32,7 +32,7 @@ class DefaultRsaKeyAlgorithmTest { @Test void testValidateNonRSAKey() { - SecretKey key = Jwts.KEY.A128KW.keyBuilder().build() + SecretKey key = Jwts.KEY.A128KW.key().build() for (DefaultRsaKeyAlgorithm alg : algs) { // if RSAKey interface isn't exposed (e.g. PKCS11 or HSM), don't error: alg.validate(key, true) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy index 8e09f6c4e..82a2c08a1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy @@ -66,7 +66,7 @@ class DirectKeyAlgorithmTest { void testGetDecryptionKey() { def alg = new DirectKeyAlgorithm() DecryptionKeyRequest req = createMock(DecryptionKeyRequest) - def key = Jwts.ENC.A128GCM.keyBuilder().build() + def key = Jwts.ENC.A128GCM.key().build() expect(req.getKey()).andReturn(key) replay(req) def result = alg.getDecryptionKey(req) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy index 3040acbab..e38293ee7 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy @@ -28,7 +28,7 @@ class ECCurveTest { @Test void testContainsTrue() { ECCurve curve = (ECCurve) Curves.P_256 - def pair = curve.keyPairBuilder().build() + def pair = curve.keyPair().build() ECPublicKey ecPub = (ECPublicKey) pair.getPublic() assertTrue(curve.contains(ecPub.getW())) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy index 3a628074a..b3b235063 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy @@ -28,7 +28,7 @@ class EcPublicJwkFactoryTest { @Test void testCurveMissing() { try { - Jwks.builder().set(['kty': 'EC']).build() + Jwks.builder().add(['kty': 'EC']).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'crv' (Curve) value." @@ -39,7 +39,7 @@ class EcPublicJwkFactoryTest { @Test void testXMissing() { try { - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256']).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256']).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'x' (X Coordinate) value." @@ -51,7 +51,7 @@ class EcPublicJwkFactoryTest { void testYMissing() { try { String encoded = DefaultEcPublicJwk.X.applyTo(BigInteger.ONE) - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256', 'x': encoded]).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256', 'x': encoded]).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'y' (Y Coordinate) value." @@ -63,7 +63,7 @@ class EcPublicJwkFactoryTest { void testPointNotOnCurve() { try { String encoded = DefaultEcPublicJwk.X.applyTo(BigInteger.ONE) - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256', 'x': encoded, 'y': encoded]).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256', 'x': encoded, 'y': encoded]).build() fail() } catch (InvalidKeyException expected) { String msg = "EC JWK x,y coordinates do not exist on elliptic curve 'P-256'. " + diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy index 6363b7d05..8854443aa 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy @@ -112,7 +112,7 @@ class EcSignatureAlgorithmTest { @Test void testSignWithInvalidKeyFieldLength() { - def keypair = Jwts.SIG.ES256.keyPairBuilder().build() + def keypair = Jwts.SIG.ES256.keyPair().build() def data = "foo".getBytes(StandardCharsets.UTF_8) def req = new DefaultSecureRequest(data, null, null, keypair.private) try { @@ -130,7 +130,7 @@ class EcSignatureAlgorithmTest { void testVerifyWithPrivateKey() { byte[] data = 'foo'.getBytes(StandardCharsets.UTF_8) algs().each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() def key = pair.getPrivate() def signRequest = new DefaultSecureRequest(data, null, null, key) byte[] signature = it.digest(signRequest) @@ -280,7 +280,7 @@ class EcSignatureAlgorithmTest { void verifySwarmTest() { algs().each { alg -> def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() assertNotNull keypair assertTrue keypair.getPublic() instanceof ECPublicKey assertTrue keypair.getPrivate() instanceof ECPrivateKey @@ -442,7 +442,7 @@ class EcSignatureAlgorithmTest { void legacySignatureCompatDefaultTest() { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES512 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def signature = Signature.getInstance(alg.jcaName as String) def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) signature.initSign(keypair.private) @@ -469,7 +469,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES512 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def signature = Signature.getInstance(alg.jcaName as String) def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) signature.initSign(keypair.private) @@ -488,7 +488,7 @@ class EcSignatureAlgorithmTest { byte[] forgedSig = new byte[64] def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, forgedSig) assertFalse alg.verify(request) @@ -505,7 +505,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, sig) assertFalse alg.verify(request) @@ -522,7 +522,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, sig) assertFalse alg.verify(request) @@ -534,7 +534,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def invalidSignature = Decoders.BASE64URL.decode(invalidEncodedSignature) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, invalidSignature) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy index dbd608266..ae2c9f637 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy @@ -101,8 +101,8 @@ class EcdhKeyAlgorithmTest { ECPrivateKey decryptionKey = TestKeys.ES256.pair.private as ECPrivateKey // Expected curve for this is P-256 // This uses curve P-384 instead, does not match private key, so it's unexpected: - def jwk = Jwks.builder().forKey(TestKeys.ES384.pair.public as ECPublicKey).build() - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + def jwk = Jwks.builder().key(TestKeys.ES384.pair.public as ECPublicKey).build() + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader DecryptionKeyRequest req = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, decryptionKey) @@ -136,8 +136,8 @@ class EcdhKeyAlgorithmTest { void testDecryptionWithInvalidPrivateKey() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.RS256.pair.private as PrivateKey // not an elliptic curve key, must fail - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -169,8 +169,8 @@ class EcdhKeyAlgorithmTest { void testECDecryptionWithNonECEpk() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.ES256.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -189,8 +189,8 @@ class EcdhKeyAlgorithmTest { void testEdwardsDecryptionWithNonEdwardsEpk() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -209,8 +209,8 @@ class EcdhKeyAlgorithmTest { void testEdwardsDecryptionWithEpkOnDifferentCurve() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.X448.pair.public as PublicKey).build() // epk is not on X25519 - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + def jwk = Jwks.builder().key(TestKeys.X448.pair.public as PublicKey).build() // epk is not on X25519 + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy index 50465bf6c..6f1f8f65f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy @@ -54,7 +54,7 @@ class EdSignatureAlgorithmTest { @Test void testKeyPairBuilder() { algs.each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() assertNotNull pair.public assertTrue pair.public instanceof PublicKey String alg = pair.public.getAlgorithm() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy index cd156800c..9def66ca5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy @@ -361,7 +361,7 @@ class EdwardsCurveTest { @Test void testDerivePublicKeyFromPrivateKey() { for(def curve : EdwardsCurve.VALUES) { - def pair = curve.keyPairBuilder().build() // generate a standard key pair using the JCA APIs + def pair = curve.keyPair().build() // generate a standard key pair using the JCA APIs def pubKey = pair.getPublic() def derivedPubKey = EdwardsCurve.derivePublic(pair.getPrivate()) // ensure our derived key matches the original JCA one: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy index 3118451c3..de4640e9e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy @@ -26,7 +26,7 @@ class EdwardsPublicKeyDeriverTest { @Test void testDeriveWithNonEdwardsKey() { - def rsaPrivKey = Jwts.SIG.RS256.keyPairBuilder().build().getPrivate() + def rsaPrivKey = Jwts.SIG.RS256.keyPair().build().getPrivate() try { EdwardsPublicKeyDeriver.INSTANCE.apply(rsaPrivKey) fail() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy index 343b97f6a..250664182 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy @@ -35,12 +35,12 @@ class FixedSecretKeyBuilder implements SecretKeyBuilder { } @Override - SecretKeyBuilder setProvider(Provider provider) { + SecretKeyBuilder provider(Provider provider) { return this } @Override - SecretKeyBuilder setRandom(SecureRandom random) { + SecretKeyBuilder random(SecureRandom random) { return this } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy index 70566cda9..2c8be5ea9 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy @@ -54,7 +54,7 @@ class HashAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForKeyWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist reg.forKey('invalid') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy index 4448831f9..f7bc165bf 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy @@ -48,7 +48,7 @@ class HmacAesAeadAlgorithmTest { Jwts.ENC.A256CBC_HS512 ] for (AeadAlgorithm alg : algs) { - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() assertEquals alg.getKeyBitLength(), Bytes.bitLength(key.getEncoded()) } } @@ -58,7 +58,7 @@ class HmacAesAeadAlgorithmTest { def alg = Jwts.ENC.A128CBC_HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() def plaintext = "Hello World! Nice to meet you!".getBytes("UTF-8") diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy index b542111e7..181614a48 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy @@ -39,7 +39,7 @@ class JwkConverterTest { @Test void testSecretJwkTypeString() { - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() assertEquals 'Secret JWK', typeString(jwk) } @@ -86,7 +86,7 @@ class JwkConverterTest { @Test void testPrivateJwk() { JwkConverter converter = new JwkConverter<>(PrivateJwk.class) - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() try { converter.applyFrom(jwk) fail() @@ -99,7 +99,7 @@ class JwkConverterTest { @Test void testRsaPrivateJwk() { JwkConverter converter = new JwkConverter<>(RsaPublicJwk.class) - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() try { converter.applyFrom(jwk) fail() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy index 9904b870f..e2479e3c2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy @@ -88,7 +88,7 @@ class JwkSerializationTest { static void testSecretJwk(Serializer serializer, Deserializer deserializer) { def key = TestKeys.A128GCM - def jwk = Jwks.builder().forKey(key).setId('id').build() + def jwk = Jwks.builder().key(key).id('id').build() assertWrapped(jwk, ['k']) // Ensure no Groovy or Java toString prints out secret values: @@ -105,7 +105,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertTrue jwk.k instanceof Supplier assertEquals jwk, jwk2 assertEquals jwk.k, jwk2.k @@ -114,7 +114,7 @@ class JwkSerializationTest { static void testPrivateEcJwk(Serializer serializer, Deserializer deserializer) { - def jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).setId('id').build() + def jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).id('id').build() assertWrapped(jwk, ['d']) // Ensure no Groovy or Java toString prints out secret values: @@ -136,7 +136,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertTrue jwk.d instanceof Supplier assertEquals jwk, jwk2 assertEquals jwk.d, jwk2.d @@ -164,7 +164,7 @@ class JwkSerializationTest { static void testPrivateRsaJwk(Serializer serializer, Deserializer deserializer) { - def jwk = Jwks.builder().forRsaKeyPair(TestKeys.RS256.pair).setId('id').build() + def jwk = Jwks.builder().rsaKeyPair(TestKeys.RS256.pair).id('id').build() def privateFieldNames = ['d', 'p', 'q', 'dp', 'dq', 'qi'] assertWrapped(jwk, privateFieldNames) @@ -191,7 +191,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertEquals(jwk, jwk2, privateFieldNames) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy index d272351df..775c311b5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy @@ -44,7 +44,7 @@ class JwkThumbprintsTest { @Test void testSecretJwks() { TestKeys.SECRET.each { SecretKey key -> - def jwk = Jwks.builder().forKey((SecretKey) key).setIdFromThumbprint().build() + def jwk = Jwks.builder().key((SecretKey) key).idFromThumbprint().build() def json = RfcTests.stripws(""" {"k":"${jwk.get('k').get()}","kty":"oct"} """) @@ -58,7 +58,7 @@ class JwkThumbprintsTest { @Test void testRsaKeyPair() { def pair = TestKeys.RS256.pair - def privJwk = Jwks.builder().forRsaKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().rsaKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"e":"${pubJwk.get('e')}","kty":"RSA","n":"${pubJwk.get('n')}"} @@ -80,7 +80,7 @@ class JwkThumbprintsTest { @Test void testEcKeyPair() { def pair = TestKeys.ES256.pair - def privJwk = Jwks.builder().forEcKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().ecKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"crv":"${pubJwk.get('crv')}","kty":"EC","x":"${pubJwk.get('x')}","y":"${pubJwk.get('y')}"} @@ -102,7 +102,7 @@ class JwkThumbprintsTest { @Test void testEdECKeyPair() { def pair = TestKeys.Ed25519.pair - def privJwk = Jwks.builder().forOctetKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().octetKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"crv":"${pubJwk.get('crv')}","kty":"OKP","x":"${pubJwk.get('x')}"} diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index 412bd1e19..af441a46a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -31,6 +31,7 @@ import java.security.cert.X509Certificate import java.security.interfaces.ECKey import java.security.interfaces.ECPublicKey import java.security.interfaces.RSAKey +import java.security.interfaces.RSAPublicKey import java.security.spec.ECParameterSpec import java.security.spec.ECPoint @@ -38,8 +39,8 @@ import static org.junit.Assert.* class JwksTest { - private static final SecretKey SKEY = Jwts.SIG.HS256.keyBuilder().build() - private static final java.security.KeyPair EC_PAIR = Jwts.SIG.ES256.keyPairBuilder().build() + private static final SecretKey SKEY = Jwts.SIG.HS256.key().build() + private static final java.security.KeyPair EC_PAIR = Jwts.SIG.ES256.keyPair().build() private static String srandom() { byte[] random = new byte[16] @@ -53,16 +54,16 @@ class JwksTest { //test non-null value: //noinspection GroovyAssignabilityCheck - def builder = Jwks.builder().forKey(key) - builder."set${cap}"(val) + def builder = Jwks.builder().key(key) + builder."$name"(val) def jwk = builder.build() assertEquals val, jwk."get${cap}"() assertEquals expectedFieldValue, jwk."${id}" //test null value: - builder = Jwks.builder().forKey(key) + builder = Jwks.builder().key(key) try { - builder."set${cap}"(null) + builder."$name"(null) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -72,10 +73,10 @@ class JwksTest { assertFalse jwk.containsKey(id) //test empty string value - builder = Jwks.builder().forKey(key) + builder = Jwks.builder().key(key) if (val instanceof String) { try { - builder."set${cap}"(' ' as String) + builder."$name"(' ' as String) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -93,7 +94,7 @@ class JwksTest { } if (val instanceof Collection) { try { - builder."set${cap}"(val) + builder."$name"(val) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -122,7 +123,7 @@ class JwksTest { @Test void testBuilderWithSecretKey() { - def jwk = Jwks.builder().forKey(SKEY).build() + def jwk = Jwks.builder().key(SKEY).build() assertEquals 'oct', jwk.getType() assertEquals 'oct', jwk.kty String k = jwk.k.get() as String @@ -171,13 +172,13 @@ class JwksTest { @Test void testRandom() { def random = new SecureRandom() - def jwk = Jwks.builder().forKey(SKEY).setRandom(random).build() + def jwk = Jwks.builder().key(SKEY).random(random).build() assertSame random, jwk.@context.getRandom() } @Test void testNullRandom() { - assertNotNull Jwks.builder().forKey(SKEY).setRandom(null).build() + assertNotNull Jwks.builder().key(SKEY).random(null).build() } static void testX509Thumbprint(int number) { @@ -186,16 +187,7 @@ class JwksTest { for (def alg : algs) { //get test cert: X509Certificate cert = TestCertificates.readTestCertificate(alg) - def pubKey = cert.getPublicKey() - - def builder = Jwks.builder() - if (pubKey instanceof ECKey) { - builder = builder.forEcChain(cert) - } else if (pubKey instanceof RSAKey) { - builder = builder.forRsaChain(cert) - } else { - builder = builder.forOctetChain(cert) - } + def builder = Jwks.builder().chain(Arrays.asList(cert)) if (number == 1) { builder.withX509Sha1Thumbprint(true) @@ -206,7 +198,7 @@ class JwksTest { assertNotNull thumbprint //ensure base64url encoding/decoding of the thumbprint works: - def jwkFromValues = Jwks.builder().set(jwkFromKey).build() as PublicJwk + def jwkFromValues = Jwks.builder().add(jwkFromKey).build() as PublicJwk assertArrayEquals thumbprint, jwkFromValues."getX509CertificateSha${number}Thumbprint"() as byte[] } } @@ -215,8 +207,8 @@ class JwksTest { void testSecretJwks() { Collection algs = Jwts.SIG.get().values().findAll({ it instanceof MacAlgorithm }) as Collection for (def alg : algs) { - SecretKey secretKey = alg.keyBuilder().build() - def jwk = Jwks.builder().forKey(secretKey).setId('id').build() + SecretKey secretKey = alg.key().build() + def jwk = Jwks.builder().key(secretKey).id('id').build() assertEquals 'oct', jwk.getType() assertTrue jwk.containsKey('k') assertEquals 'id', jwk.getId() @@ -228,7 +220,7 @@ class JwksTest { void testSecretKeyGetEncodedReturnsNull() { SecretKey key = new TestSecretKey(algorithm: "AES") try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG @@ -249,7 +241,7 @@ class JwksTest { } } try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG @@ -267,18 +259,18 @@ class JwksTest { for (def alg : algs) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() PublicKey pub = pair.getPublic() PrivateKey priv = pair.getPrivate() // test individual keys - PublicJwk pubJwk = Jwks.builder().forKey(pub).setPublicKeyUse("sig").build() + PublicJwk pubJwk = Jwks.builder().key(pub).publicKeyUse("sig").build() assertEquals pub, pubJwk.toKey() - def builder = Jwks.builder().forKey(priv).setPublicKeyUse('sig') + def builder = Jwks.builder().key(priv).publicKeyUse('sig') if (alg instanceof EdSignatureAlgorithm) { // We haven't implemented EdDSA public-key derivation yet, so public key is required - builder.setPublicKey(pub) + builder.publicKey(pub) } PrivateJwk privJwk = builder.build() assertEquals priv, privJwk.toKey() @@ -291,13 +283,13 @@ class JwksTest { // test pair if (pub instanceof ECKey) { - builder = Jwks.builder().forEcKeyPair(pair) + builder = Jwks.builder().ecKeyPair(pair) } else if (pub instanceof RSAKey) { - builder = Jwks.builder().forRsaKeyPair(pair) + builder = Jwks.builder().rsaKeyPair(pair) } else { - builder = Jwks.builder().forOctetKeyPair(pair) + builder = Jwks.builder().octetKeyPair(pair) } - privJwk = builder.setPublicKeyUse("sig").build() as PrivateJwk + privJwk = builder.publicKeyUse("sig").build() as PrivateJwk assertEquals priv, privJwk.toKey() privPubJwk = privJwk.toPublicJwk() assertEquals pubJwk, privPubJwk @@ -314,15 +306,15 @@ class JwksTest { for (SignatureAlgorithm alg : algs) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() ECPublicKey pubKey = pair.getPublic() as ECPublicKey - EcPublicJwk jwk = Jwks.builder().forKey(pubKey).build() + EcPublicJwk jwk = Jwks.builder().key(pubKey).build() //try creating a JWK with a bad point: def badPubKey = new InvalidECPublicKey(pubKey) try { - Jwks.builder().forKey(badPubKey).build() + Jwks.builder().key(badPubKey).build() } catch (InvalidKeyException ike) { String curveId = jwk.get('crv') String msg = EcPublicJwkFactory.keyContainsErrorMessage(curveId) @@ -335,7 +327,7 @@ class JwksTest { Map modified = new LinkedHashMap<>(jwk) modified.put('x', Converters.BIGINT.applyTo(x)) try { - Jwks.builder().set(modified).build() + Jwks.builder().add(modified).build() } catch (InvalidKeyException ike) { String expected = EcPublicJwkFactory.jwkContainsErrorMessage(jwk.crv as String, modified) assertEquals(expected, ike.getMessage()) @@ -345,7 +337,7 @@ class JwksTest { Map modified = new LinkedHashMap<>(jwk) modified.put('y', Converters.BIGINT.applyTo(y)) try { - Jwks.builder().set(modified).build() + Jwks.builder().add(modified).build() } catch (InvalidKeyException ike) { String expected = EcPublicJwkFactory.jwkContainsErrorMessage(jwk.crv as String, modified) assertEquals(expected, ike.getMessage()) @@ -357,8 +349,8 @@ class JwksTest { @Test void testPublicJwkBuilderWithRSAPublicKey() { def key = TestKeys.RS256.pair.public - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(RSAPublicKey) method: - def jwk = Jwks.builder().forKey((PublicKey) key).build() + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(RSAPublicKey) method: + def jwk = Jwks.builder().key((PublicKey) key).build() assertNotNull jwk assertTrue jwk instanceof RsaPublicJwk } @@ -366,8 +358,8 @@ class JwksTest { @Test void testPublicJwkBuilderWithECPublicKey() { def key = TestKeys.ES256.pair.public - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(ECPublicKey) method: - def jwk = Jwks.builder().forKey((PublicKey) key).build() + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(ECPublicKey) method: + def jwk = Jwks.builder().key((PublicKey) key).build() assertNotNull jwk assertTrue jwk instanceof EcPublicJwk } @@ -375,9 +367,9 @@ class JwksTest { @Test void testPublicJwkBuilderWithUnsupportedKey() { def key = new TestPublicKey() - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(ECPublicKey) method: + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(ECPublicKey) method: try { - Jwks.builder().forKey((PublicKey) key) + Jwks.builder().key((PublicKey) key) } catch (UnsupportedKeyException expected) { String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPublicKey with algorithm \'null\'.' assertEquals(msg, expected.getMessage()) @@ -388,8 +380,8 @@ class JwksTest { @Test void testPrivateJwkBuilderWithRSAPrivateKey() { def key = TestKeys.RS256.pair.private - // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the forKey(RSAPrivateKey) method: - def jwk = Jwks.builder().forKey((PrivateKey) key).build() + // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the key(RSAPrivateKey) method: + def jwk = Jwks.builder().key((PrivateKey) key).build() assertNotNull jwk assertTrue jwk instanceof RsaPrivateJwk } @@ -397,8 +389,8 @@ class JwksTest { @Test void testPrivateJwkBuilderWithECPrivateKey() { def key = TestKeys.ES256.pair.private - // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the forKey(ECPrivateKey) method: - def jwk = Jwks.builder().forKey((PrivateKey) key).build() + // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the key(ECPrivateKey) method: + def jwk = Jwks.builder().key((PrivateKey) key).build() assertNotNull jwk assertTrue jwk instanceof EcPrivateJwk } @@ -407,7 +399,7 @@ class JwksTest { void testPrivateJwkBuilderWithUnsupportedKey() { def key = new TestPrivateKey() try { - Jwks.builder().forKey((PrivateKey) key) + Jwks.builder().key((PrivateKey) key) } catch (UnsupportedKeyException expected) { String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPrivateKey with algorithm \'null\'.' assertEquals(msg, expected.getMessage()) @@ -415,6 +407,76 @@ class JwksTest { } } + @Test + void testEcChain() { + TestKeys.EC.each { + ECPublicKey key = it.pair.public as ECPublicKey + def jwk = Jwks.builder().ecChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testRsaChain() { + TestKeys.RSA.each { + RSAPublicKey key = it.pair.public as RSAPublicKey + def jwk = Jwks.builder().rsaChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testOctetChain() { + TestKeys.EdEC.findAll({ it -> it.cert != null }).each { // no chains for XEC keys + PublicKey key = it.pair.public + def jwk = Jwks.builder().octetChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testRsaKeyPair() { + TestKeys.RSA.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().rsaKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testEcKeyPair() { + TestKeys.EC.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().ecKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testOctetKeyPair() { + TestKeys.EdEC.findAll({ it -> it.cert != null }).each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().octetKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testKeyPair() { + TestKeys.ASYM.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().keyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + private static class InvalidECPublicKey implements ECPublicKey { private final ECPublicKey good diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy index 1975e85d9..3f8ab28a1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy @@ -62,7 +62,7 @@ class KeyPairsTest { @Test void testGetKeyECMismatch() { - KeyPair pair = Jwts.SIG.RS256.keyPairBuilder().build() + KeyPair pair = Jwts.SIG.RS256.keyPair().build() Class clazz = ECPublicKey try { KeyPairs.getKey(pair, clazz) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy index ac57b00f4..5620280fb 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy @@ -120,19 +120,19 @@ class OctetJwksTest { for (EdwardsCurve curve : EdwardsCurve.VALUES) { - def pair = curve.keyPairBuilder().build() + def pair = curve.keyPair().build() PublicKey pub = pair.getPublic() PrivateKey priv = pair.getPrivate() // test individual keys - PublicJwk pubJwk = Jwks.builder().forOctetKey(pub).setPublicKeyUse("sig").build() - PublicJwk pubValuesJwk = Jwks.builder().set(pubJwk).build() as PublicJwk // ensure value map symmetry + PublicJwk pubJwk = Jwks.builder().octetKey(pub).publicKeyUse("sig").build() + PublicJwk pubValuesJwk = Jwks.builder().add(pubJwk).build() as PublicJwk // ensure value map symmetry assertEquals pubJwk, pubValuesJwk assertEquals pub, pubJwk.toKey() assertEquals pub, pubValuesJwk.toKey() - PrivateJwk privJwk = Jwks.builder().forOctetKey(priv).setPublicKey(pub).setPublicKeyUse("sig").build() - PrivateJwk privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry + PrivateJwk privJwk = Jwks.builder().octetKey(priv).publicKey(pub).publicKeyUse("sig").build() + PrivateJwk privValuesJwk = Jwks.builder().add(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() // we can't assert that priv.equals(privValuesJwk.toKey()) here because BouncyCastle uses PKCS8 V2 encoding @@ -159,8 +159,8 @@ class OctetJwksTest { assertArrayEquals privMaterial, jwkKeyMaterial // Test public-to-private builder coercion: - privJwk = Jwks.builder().forOctetKey(pub).setPrivateKey(priv).setPublicKeyUse('sig').build() - privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry + privJwk = Jwks.builder().octetKey(pub).privateKey(priv).publicKeyUse('sig').build() + privValuesJwk = Jwks.builder().add(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() // see comments above about material equality instead of encoding equality @@ -176,7 +176,7 @@ class OctetJwksTest { assertEquals pub, pubValuesJwk.toKey() // test pair - privJwk = Jwks.builder().forOctetKeyPair(pair).setPublicKeyUse("sig").build() + privJwk = Jwks.builder().octetKeyPair(pair).publicKeyUse("sig").build() assertEquals priv, privJwk.toKey() // see comments above about material equality instead of encoding equality privMaterial = curve.getKeyMaterial(priv) @@ -197,8 +197,8 @@ class OctetJwksTest { @Test void testUnknownCurveId() { def b = Jwks.builder() - .set(AbstractJwk.KTY.getId(), DefaultOctetPublicJwk.TYPE_VALUE) - .set(DefaultOctetPublicJwk.CRV.getId(), 'foo') + .add(AbstractJwk.KTY.getId(), DefaultOctetPublicJwk.TYPE_VALUE) + .add(DefaultOctetPublicJwk.CRV.getId(), 'foo') try { b.build() fail() @@ -217,7 +217,7 @@ class OctetJwksTest { def priv = TestKeys.X448.pair.private def mismatchedPub = TestKeys.X25519.pair.public try { - Jwks.builder().forOctetKey(priv).setPublicKey(mismatchedPub).build() + Jwks.builder().octetKey(priv).publicKey(mismatchedPub).build() fail() } catch (InvalidKeyException ike) { String msg = "Specified Edwards Curve PublicKey does not match the specified PrivateKey's curve." diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy index 1cac539d2..e2bbd5846 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy @@ -91,7 +91,7 @@ class PasswordSpecTest { @Test void testEquals() { - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY, key2 assertNotEquals KEY, new Object() @@ -99,14 +99,14 @@ class PasswordSpecTest { @Test void testIdentityEquals() { - Password key = Keys.forPassword(PASSWORD) + Password key = Keys.password(PASSWORD) assertTrue key.equals(key) assertNotEquals KEY, new Object() } @Test void testHashCode() { - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY.hashCode(), key2.hashCode() } @@ -114,7 +114,7 @@ class PasswordSpecTest { @Test void testToString() { assertEquals '', KEY.toString() - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY.toString(), key2.toString() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy index af445438d..33513d5f8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy @@ -29,7 +29,7 @@ import static org.junit.Assert.fail @SuppressWarnings('SpellCheckingInspection') class Pbes2HsAkwAlgorithmTest { - private static Password KEY = Keys.forPassword("12345678".toCharArray()) + private static Password KEY = Keys.password("12345678".toCharArray()) private static List ALGS = [Jwts.KEY.PBES2_HS256_A128KW, Jwts.KEY.PBES2_HS384_A192KW, Jwts.KEY.PBES2_HS512_A256KW] as List @@ -38,7 +38,7 @@ class Pbes2HsAkwAlgorithmTest { void testInsufficientIterations() { for (Pbes2HsAkwAlgorithm alg : ALGS) { int iterations = 50 // must be 1000 or more - def header = Jwts.header().setPbes2Count(iterations) as DefaultJweHeaderMutator + def header = Jwts.header().pbes2Count(iterations) as DefaultJweHeaderMutator def mutable = new DefaultMutableJweHeader(header) KeyRequest req = new DefaultKeyRequest<>(KEY, null, null, mutable, Jwts.ENC.A256GCM) try { @@ -66,8 +66,8 @@ class Pbes2HsAkwAlgorithmTest { //double scale = 0.5035246727 def password = 'hellowor'.toCharArray() - def header = new DefaultJweHeader().setPbes2Count(iterations) - def key = Keys.forPassword(password) + def header = new DefaultJweHeader().pbes2Count(iterations) + def key = Keys.password(password) def req = new DefaultKeyRequest(null, null, key, header, Jwts.ENC.A128GCM) int sum = 0 for (int i = 0; i < tries; i++) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy index 9f721f9a3..614fb091e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy @@ -171,7 +171,7 @@ class RFC7516AppendixA1Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk + RsaPrivateJwk jwk = Jwks.builder().add(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy index 0734932ac..055e3e073 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy @@ -165,7 +165,7 @@ class RFC7516AppendixA2Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk + RsaPrivateJwk jwk = Jwks.builder().add(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy index 7ea4022fe..cf4523aa2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy @@ -105,7 +105,7 @@ class RFC7516AppendixA3Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - SecretJwk jwk = Jwks.builder().set(KEK_VALUES).build() as SecretJwk + SecretJwk jwk = Jwks.builder().add(KEK_VALUES).build() as SecretJwk SecretKey kek = jwk.toKey() // test decryption per the RFC @@ -124,7 +124,7 @@ class RFC7516AppendixA3Test { } @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(CEK) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy index 6db0f079e..c27e1373a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy @@ -58,7 +58,7 @@ class RFC7517AppendixA1Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - EcPublicJwk ecPubJwk = Jwks.builder().set(m).build() as EcPublicJwk + EcPublicJwk ecPubJwk = Jwks.builder().add(m).build() as EcPublicJwk assertTrue ecPubJwk.toKey() instanceof ECPublicKey assertEquals m.size(), ecPubJwk.size() assertEquals m.kty, ecPubJwk.getType() @@ -69,7 +69,7 @@ class RFC7517AppendixA1Test { assertEquals m.kid, ecPubJwk.getId() m = keys[1] - RsaPublicJwk rsaPublicJwk = Jwks.builder().set(m).build() as RsaPublicJwk + RsaPublicJwk rsaPublicJwk = Jwks.builder().add(m).build() as RsaPublicJwk assertTrue rsaPublicJwk.toKey() instanceof RSAPublicKey assertEquals m.size(), rsaPublicJwk.size() assertEquals m.kty, rsaPublicJwk.getType() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy index 69d2747b6..b3321944b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy @@ -88,7 +88,7 @@ class RFC7517AppendixA2Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - def jwk = Jwks.builder().set(m).build() as EcPrivateJwk + def jwk = Jwks.builder().add(m).build() as EcPrivateJwk def key = jwk.toKey() int fieldSize = key.params.curve.field.fieldSize assertTrue key instanceof ECPrivateKey @@ -105,7 +105,7 @@ class RFC7517AppendixA2Test { assertEquals m.kid, jwk.getId() m = keys[1] - jwk = Jwks.builder().set(m).build() as RsaPrivateJwk + jwk = Jwks.builder().add(m).build() as RsaPrivateJwk key = jwk.toKey() as RSAPrivateCrtKey assertNotNull key assertEquals m.size(), jwk.size() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy index 0658bd8fb..8537c01d8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy @@ -51,7 +51,7 @@ class RFC7517AppendixA3Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - SecretJwk jwk = Jwks.builder().set(m).build() as SecretJwk + SecretJwk jwk = Jwks.builder().add(m).build() as SecretJwk def key = jwk.toKey() as SecretKey assertNotNull key assertEquals m.size(), jwk.size() @@ -61,7 +61,7 @@ class RFC7517AppendixA3Test { assertEquals m.k, encode(key) m = keys[1] - jwk = Jwks.builder().set(m).build() as SecretJwk + jwk = Jwks.builder().add(m).build() as SecretJwk key = jwk.toKey() as SecretKey assertNotNull key assertEquals m.size(), jwk.size() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy index 1bed3ac9a..fb094de9b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy @@ -66,7 +66,7 @@ class RFC7517AppendixBTest { @Test void test() { def m = jwkPairs - RsaPublicJwk jwk = Jwks.builder().set(m).build() as RsaPublicJwk + RsaPublicJwk jwk = Jwks.builder().add(m).build() as RsaPublicJwk RSAPublicKey key = jwk.toKey() assertNotNull key assertEquals m.size(), jwk.size() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy index b5303a34b..f9c711f0e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -284,7 +284,7 @@ class RFC7517AppendixCTest { //ensure that the KeyAlgorithm reflects test harness values: def enc = new HmacAesAeadAlgorithm(128) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(RFC_CEK) } @@ -319,13 +319,13 @@ class RFC7517AppendixCTest { } } - Password key = Keys.forPassword(RFC_SHARED_PASSPHRASE.toCharArray()) + Password key = Keys.password(RFC_SHARED_PASSPHRASE.toCharArray()) String compact = Jwts.builder() .setPayload(RFC_JWK_JSON) - .header().setContentType('jwk+json').setPbes2Count(RFC_P2C).and() + .header().contentType('jwk+json').pbes2Count(RFC_P2C).and() .encryptWith(key, alg, enc) - .serializeToJsonWith(serializer) //ensure header created as expected with an assertion serializer + .serializer(serializer) //ensure header created as expected with an assertion serializer .compact() assertEquals RFC_COMPACT_JWE, compact diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy index 9880e3f7d..f312a5332 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy @@ -48,7 +48,7 @@ class RFC7518AppendixCTest { private static EcPrivateJwk readJwk(String json) { Map m = fromJson(json) - return Jwks.builder().set(m).build() as EcPrivateJwk + return Jwks.builder().add(m).build() as EcPrivateJwk } // https://www.rfc-editor.org/rfc/rfc7517.html#appendix-C.1 @@ -112,7 +112,7 @@ class RFC7518AppendixCTest { } String jwe = Jwts.builder() - .header().setAgreementPartyUInfo("Alice").setAgreementPartyVInfo("Bob").and() + .header().agreementPartyUInfo("Alice").agreementPartyVInfo("Bob").and() .claim("Hello", "World") .encryptWith(bobJwk.toPublicJwk().toKey(), alg, Jwts.ENC.A128GCM) .compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy index aa827f95d..20dc16a59 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy @@ -218,8 +218,8 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .header().setKeyId(jwk.getId()).and() + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -257,8 +257,8 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', kid) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(kid).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -303,8 +303,8 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -348,8 +348,8 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -386,8 +386,8 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy index 89d2d2a11..98aa58110 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -472,8 +472,8 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) .compact() @@ -536,8 +536,8 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) .compact() @@ -555,7 +555,7 @@ class RFC7520Section5Test { @Test void testSection5_3() { - def key = Keys.forPassword(FIGURE_96.toCharArray()) + def key = Keys.password(FIGURE_96.toCharArray()) String cty = 'jwk-set+json' int p2c = 8192 @@ -597,8 +597,8 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .header().setContentType(cty).setPbes2Count(p2c).and() + .serializer(serializer) // assert input, return RFC ordered string + .header().contentType(cty).pbes2Count(p2c).and() .setPayload(FIGURE_95) .encryptWith(key, alg, enc) .compact() @@ -659,8 +659,8 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .serializer(serializer) // assert input, return RFC ordered string + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(encKey, alg, enc) .compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy index 7e6f99da1..8a2773426 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy @@ -73,7 +73,7 @@ class RFC8037AppendixATest { PrivateKey privKey = privJwk.toKey() as PrivateKey PublicKey pubKey = privJwk.toPublicJwk().toKey() as PublicKey - def builtPrivJwk = Jwks.builder().forKey(privKey).setPublicKey(pubKey).build() + def builtPrivJwk = Jwks.builder().key(privKey).publicKey(pubKey).build() //output should equal RFC input: assertEquals privJwk, builtPrivJwk @@ -102,7 +102,7 @@ class RFC8037AppendixATest { void test_Sections_A4_and_A5() { def privJwk = a1Jwk() String compact = Jwts.builder() - .setContent(A4_JWS_PAYLOAD.getBytes(StandardCharsets.UTF_8)) + .content(A4_JWS_PAYLOAD.getBytes(StandardCharsets.UTF_8)) .signWith(privJwk.toKey() as PrivateKey, Jwts.SIG.EdDSA) .compact() assertEquals A4_JWS_COMPACT, compact @@ -128,7 +128,7 @@ class RFC8037AppendixATest { def bobPrivKeyHex = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb' //convert these two values to a JWK for convenient reference: - def bobPrivJwk = Jwks.builder().set([ + def bobPrivJwk = Jwks.builder().add([ kty: "OKP", crv: "X25519", kid: "Bob", x : bobPubKeyHex.decodeHex().encodeBase64Url() as String, d : bobPrivKeyHex.decodeHex().encodeBase64Url() as String @@ -144,7 +144,7 @@ class RFC8037AppendixATest { 0d bf 3a 0d 26 38 1a f4 eb a4 a9 8e aa 9b 4e 6a''') //Turn these two values into a Java KeyPair, and ensure it is used during key algorithm execution: - final OctetPrivateJwk ephemJwk = Jwks.builder().set([ + final OctetPrivateJwk ephemJwk = Jwks.builder().add([ kty: "OKP", crv: "X25519", x : rfcEphemeralPubKeyHex.decodeHex().encodeBase64Url() as String, @@ -165,7 +165,7 @@ class RFC8037AppendixATest { // Create the test case JWE with the 'kid' header to ensure the output matches the RFC expected value: String jwe = Jwts.builder() - .setHeaderParam('kid', bobPrivJwk.getId()) + .header().keyId(bobPrivJwk.getId()).and() .setIssuer(issuer) .encryptWith(bobPrivJwk.toPublicJwk().toKey() as PublicKey, alg, Jwts.ENC.A128GCM) .compact() @@ -215,7 +215,7 @@ class RFC8037AppendixATest { def bobPrivKeyHex = '1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d' //convert these two values to a JWK for convenient reference: - def bobPrivJwk = Jwks.builder().set([ + def bobPrivJwk = Jwks.builder().add([ kty: "OKP", crv: "X448", kid: "Dave", // "Dave" instead of expected "Bob" x : bobPubKeyHex.decodeHex().encodeBase64Url() as String, d : bobPrivKeyHex.decodeHex().encodeBase64Url() as String @@ -235,7 +235,7 @@ class RFC8037AppendixATest { 17 7f 80 e5 32 c4 1f a0''') //Turn these two values into a Java KeyPair, and ensure it is used during key algorithm execution: - final OctetPrivateJwk ephemJwk = Jwks.builder().set([ + final OctetPrivateJwk ephemJwk = Jwks.builder().add([ kty: "OKP", crv: "X448", x : rfcEphemeralPubKeyHex.decodeHex().encodeBase64Url() as String, @@ -256,7 +256,7 @@ class RFC8037AppendixATest { // Create the test case JWE with the 'kid' header to ensure the output matches the RFC expected value: String jwe = Jwts.builder() - .setHeaderParam('kid', bobPrivJwk.getId()) //value will be "Dave" as noted above + .header().keyId(bobPrivJwk.getId()).and() //value will be "Dave" as noted above .setIssuer(issuer) .encryptWith(bobPrivJwk.toPublicJwk().toKey() as PublicKey, alg, Jwts.ENC.A256GCM) .compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy index f5a8bca96..ade8312fc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy @@ -44,7 +44,7 @@ class RsaPrivateJwkFactoryTest { } try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String msg = 'Unable to derive RSAPublicKey from RSAPrivateKey implementation ' + @@ -119,7 +119,7 @@ class RsaPrivateJwkFactoryTest { } as RSAPrivateKey try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String prefix = 'Unable to derive RSAPublicKey from RSAPrivateKey {kty=RSA}. Cause: ' @@ -139,7 +139,7 @@ class RsaPrivateJwkFactoryTest { //build up test key: RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, infos) - RsaPrivateJwk jwk = Jwks.builder().forKey(key).build() + RsaPrivateJwk jwk = Jwks.builder().key(key).build() List oth = jwk.get('oth') as List assertTrue oth instanceof List @@ -162,11 +162,11 @@ class RsaPrivateJwkFactoryTest { RSAPrivateCrtKey priv = pair.private as RSAPrivateCrtKey RSAPublicKey pub = pair.public as RSAPublicKey - RsaPrivateJwk jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + RsaPrivateJwk jwk = Jwks.builder().key(priv).publicKey(pub).build() // an RSAMultiPrimePrivateCrtKey without OtherInfo elements is treated the same as a normal RSAPrivateCrtKey, // so ensure they are equal: RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, null) - RsaPrivateJwk jwk2 = Jwks.builder().forKey(key).setPublicKey(pub).build() + RsaPrivateJwk jwk2 = Jwks.builder().key(key).publicKey(pub).build() assertEquals jwk, jwk2 assertNull jwk.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId()) assertNull jwk2.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId()) @@ -181,7 +181,7 @@ class RsaPrivateJwkFactoryTest { def priv = new TestRSAPrivateKey(privCrtKey) - RsaPrivateJwk jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + RsaPrivateJwk jwk = Jwks.builder().key(priv).publicKey(pub).build() assertEquals 4, jwk.size() // kty, public exponent, modulus, private exponent assertEquals 'RSA', jwk.getType() assertEquals Converters.BIGINT.applyTo(pub.getModulus()), jwk.get(DefaultRsaPublicJwk.MODULUS.getId()) @@ -194,13 +194,13 @@ class RsaPrivateJwkFactoryTest { def pair = TestKeys.RS256.pair RSAPublicKey pub = pair.public as RSAPublicKey RSAPrivateKey priv = new TestRSAPrivateKey(pair.private as RSAPrivateKey) - def jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + def jwk = Jwks.builder().key(priv).publicKey(pub).build() //minimal values: kty, modulus, public exponent, private exponent = 4 fields: assertEquals 4, jwk.size() def map = new LinkedHashMap(jwk) assertEquals 4, map.size() - def jwkFromValues = Jwks.builder().set(map).build() + def jwkFromValues = Jwks.builder().add(map).build() //ensure they're equal: assertEquals jwk, jwkFromValues @@ -217,7 +217,7 @@ class RsaPrivateJwkFactoryTest { def infos = [info1, info2] RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, infos) - final RsaPrivateJwk jwk = Jwks.builder().forKey(key).setPublicKey(pub).build() + final RsaPrivateJwk jwk = Jwks.builder().key(key).publicKey(pub).build() //we have to test the class directly and override, since the dummy MultiPrime values won't be accepted by the //JVM: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy index 4e5ff7444..10e765b01 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy @@ -39,7 +39,7 @@ class RsaSignatureAlgorithmTest { @Test void testKeyPairBuilder() { algs().each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() assertNotNull pair.public assertTrue pair.public instanceof RSAPublicKey assertEquals it.preferredKeyBitLength, pair.public.modulus.bitLength() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy index b2cd99e08..f047f2d25 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy @@ -32,22 +32,22 @@ class SecretJwkFactoryTest { @Test // if a jwk does not have an 'alg' or 'use' field, we default to an AES key void testNoAlgNoSigJcaName() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() + SecretJwk result = Jwks.builder().add(jwk).build() as SecretJwk assertEquals 'AES', result.toKey().getAlgorithm() } @Test void testJwkHS256AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS256').build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS256').build() as SecretJwk assertEquals 'HmacSHA256', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA256() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA256', result.toKey().getAlgorithm() @@ -55,15 +55,15 @@ class SecretJwkFactoryTest { @Test void testJwkHS384AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS384').build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS384').build() as SecretJwk assertEquals 'HmacSHA384', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA384() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA384', result.toKey().getAlgorithm() @@ -71,15 +71,15 @@ class SecretJwkFactoryTest { @Test void testJwkHS512AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS512').build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS512').build() as SecretJwk assertEquals 'HmacSHA512', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA512() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA512', result.toKey().getAlgorithm() @@ -87,37 +87,37 @@ class SecretJwkFactoryTest { @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA256 void testNoAlgAndSigUseForHS256() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA256', result.toKey().getAlgorithm() // jcaName has been changed to a sig algorithm } @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA384 void testNoAlgAndSigUseForHS384() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA384', result.toKey().getAlgorithm() } @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA512 void testNoAlgAndSigUseForHS512() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA512', result.toKey().getAlgorithm() } @Test // no 'alg' jwk property, but 'use' is something other than 'sig', so jcaName should default to AES void testNoAlgAndNonSigUse() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'foo').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'foo').build() as SecretJwk assertEquals 'AES', result.toKey().getAlgorithm() } @@ -129,12 +129,12 @@ class SecretJwkFactoryTest { void testSizeMismatchedSecretJwk() { //first get a valid HS256 JWK: - SecretJwk validJwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk validJwk = Jwks.builder().key(TestKeys.HS256).build() //now associate it with an alg identifier that is more than the key is capable of: try { - Jwks.builder().set(validJwk) - .set('alg', 'HS384') + Jwks.builder().add(validJwk) + .add('alg', 'HS384') .build() fail() } catch (MalformedKeyException expected) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy index 759782984..384d87df0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy @@ -36,23 +36,23 @@ class TestKeys { // ======================================================= // Secret Keys // ======================================================= - static SecretKey HS256 = Jwts.SIG.HS256.keyBuilder().build() - static SecretKey HS384 = Jwts.SIG.HS384.keyBuilder().build() - static SecretKey HS512 = Jwts.SIG.HS512.keyBuilder().build() + static SecretKey HS256 = Jwts.SIG.HS256.key().build() + static SecretKey HS384 = Jwts.SIG.HS384.key().build() + static SecretKey HS512 = Jwts.SIG.HS512.key().build() static Collection HS = Collections.setOf(HS256, HS384, HS512) static SecretKey A128GCM, A192GCM, A256GCM, A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW static Collection AGCM static { - A128GCM = A128KW = A128GCMKW = Jwts.ENC.A128GCM.keyBuilder().build() - A192GCM = A192KW = A192GCMKW = Jwts.ENC.A192GCM.keyBuilder().build() - A256GCM = A256KW = A256GCMKW = Jwts.ENC.A256GCM.keyBuilder().build() + A128GCM = A128KW = A128GCMKW = Jwts.ENC.A128GCM.key().build() + A192GCM = A192KW = A192GCMKW = Jwts.ENC.A192GCM.key().build() + A256GCM = A256KW = A256GCMKW = Jwts.ENC.A256GCM.key().build() AGCM = Collections.setOf(A128GCM, A192GCM, A256GCM) } - static SecretKey A128CBC_HS256 = Jwts.ENC.A128CBC_HS256.keyBuilder().build() - static SecretKey A192CBC_HS384 = Jwts.ENC.A192CBC_HS384.keyBuilder().build() - static SecretKey A256CBC_HS512 = Jwts.ENC.A256CBC_HS512.keyBuilder().build() + static SecretKey A128CBC_HS256 = Jwts.ENC.A128CBC_HS256.key().build() + static SecretKey A192CBC_HS384 = Jwts.ENC.A192CBC_HS384.key().build() + static SecretKey A256CBC_HS512 = Jwts.ENC.A256CBC_HS512.key().build() static Collection ACBC = Collections.setOf(A128CBC_HS256, A192CBC_HS384, A256CBC_HS512) static Collection SECRET = new LinkedHashSet<>() diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy index 6b1301a9a..89bca4ac5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy @@ -86,7 +86,7 @@ class EncryptionAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForIdWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist registry.forKey('invalid') } @@ -108,7 +108,7 @@ class EncryptionAlgorithmsTest { for (AeadAlgorithm alg : registry.values()) { - def key = alg.keyBuilder().build() + def key = alg.key().build() def request = new DefaultAeadRequest(PLAINTEXT_BYTES, key, null) @@ -138,7 +138,7 @@ class EncryptionAlgorithmsTest { for (AeadAlgorithm alg : registry.values()) { - def key = alg.keyBuilder().build() + def key = alg.key().build() def req = new DefaultAeadRequest(PLAINTEXT_BYTES, null, null, key, AAD_BYTES) diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy index 4502c6bac..254e2fa1a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy @@ -72,7 +72,7 @@ class KeyAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForKeyWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist Jwts.KEY.get().forKey('invalid') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy index 7d3268e7b..5d1b0778d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy @@ -73,8 +73,8 @@ class KeysTest { "is not secure enough for any JWT HMAC-SHA algorithm. The JWT " + "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " + "size >= 256 bits (the key size must be greater than or equal to the hash " + - "output size). Consider using the Jwts.SIG.HS256.keyBuilder() method (or " + - "HS384.keyBuilder() or HS512.keyBuilder()) to create a key guaranteed to be secure enough " + + "output size). Consider using the Jwts.SIG.HS256.key() builder (or " + + "HS384.key() or HS512.key()) to create a key guaranteed to be secure enough " + "for your preferred HMAC-SHA algorithm. See " + "https://tools.ietf.org/html/rfc7518#section-3.2 for more information." as String, expected.message } @@ -131,7 +131,7 @@ class KeysTest { void testSecretKeyFor() { for (SecureDigestAlgorithm alg : Jwts.SIG.get().values()) { if (alg instanceof MacAlgorithm) { - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() assertEquals alg.getKeyBitLength(), Bytes.bitLength(key.getEncoded()) assertEquals alg.jcaName, key.algorithm assertEquals alg, DefaultJwtBuilder.forSigningKey(key) // https://github.com/jwtk/jjwt/issues/381 @@ -211,7 +211,7 @@ class KeysTest { if (alg instanceof RsaSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair PublicKey pub = pair.getPublic() @@ -224,7 +224,7 @@ class KeysTest { } else if (alg instanceof EdSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair PublicKey pub = pair.getPublic() @@ -237,7 +237,7 @@ class KeysTest { } else if (alg instanceof EcSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair int len = alg.orderBitLength @@ -276,7 +276,7 @@ class KeysTest { @Test void testForPassword() { def password = "whatever".toCharArray() - Password key = Keys.forPassword(password) + Password key = Keys.password(password) assertArrayEquals password, key.toCharArray() assertTrue key instanceof PasswordSpec } diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md index 81428ba83..6677b7e57 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md @@ -33,7 +33,7 @@ The Elliptic Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this direct openssl x509 -pubkey -noout -in ES384.crt.pem > ES384.pub.pem openssl x509 -pubkey -noout -in ES512.crt.pem > ES512.pub.pem -The Edwards Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this directory were created for testing as follows +The Edwards Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this directory were created for testing as follows. Note that we don't/can't create self-signed certificates (`*.crt.pem` files) for X25519 and X448 because these algorithms cannot be used for signing (perhaps we could have signed them with another key, but it wasn't necessary for our testing): diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index d1850ea49..b846d1252 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -61,13 +61,13 @@ public class JavaReadmeTest { public void testExampleJwsHS() { // Create a test key suitable for the desired HMAC-SHA algorithm: MacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256 - SecretKey key = alg.keyBuilder().build(); + SecretKey key = alg.key().build(); String message = "Hello World!"; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWS: - String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); + String jws = Jwts.builder().content(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); @@ -82,7 +82,7 @@ public void testExampleJwsHS() { public void testExampleJwsRSA() { // Create a test key suitable for the desired RSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc... - KeyPair pair = alg.keyPairBuilder().build(); + KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his RSA private key: String jws = Jwts.builder().setSubject("Alice") @@ -104,7 +104,7 @@ public void testExampleJwsRSA() { public void testExampleJwsECDSA() { // Create a test key suitable for the desired ECDSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384 - KeyPair pair = alg.keyPairBuilder().build(); + KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his EC private key: String jws = Jwts.builder().setSubject("Alice") @@ -127,13 +127,13 @@ public void testExampleJweDir() { // Create a test key suitable for the desired payload encryption algorithm: // (A*GCM algorithms are recommended, but require JDK 8 or later) AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A128GCM, A192GCM, A256CBC-HS512, etc... - SecretKey key = enc.keyBuilder().build(); + SecretKey key = enc.key().build(); String message = "Live long and prosper."; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWE: - String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); + String jwe = Jwts.builder().content(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); @@ -147,7 +147,7 @@ public void testExampleJweDir() { @Test public void testExampleJweRSA() { // Create a test KeyPair suitable for the desired RSA key algorithm: - KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.RS512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP or RSA1_5 @@ -174,7 +174,7 @@ public void testExampleJweRSA() { public void testExampleJweAESKW() { // Create a test SecretKey suitable for the desired AES Key Wrap algorithm: SecretKeyAlgorithm alg = Jwts.KEY.A256GCMKW; //or A192GCMKW, A128GCMKW, A256KW, etc... - SecretKey key = alg.keyBuilder().build(); + SecretKey key = alg.key().build(); // Chooose the Encryption Algorithm used to encrypt the payload: AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... @@ -195,7 +195,7 @@ public void testExampleJweAESKW() { @Test public void testExampleJweECDHES() { // Create a test KeyPair suitable for the desired EC key algorithm: - KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.ES512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc... @@ -222,7 +222,7 @@ public void testExampleJweECDHES() { public void testExampleJwePassword() { //DO NOT use this example password in a real app, it is well-known to password crackers String pw = "correct horse battery staple"; - Password password = Keys.forPassword(pw.toCharArray()); + Password password = Keys.password(pw.toCharArray()); // Choose the desired PBES2 key derivation algorithm: KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_HS384... @@ -241,7 +241,7 @@ public void testExampleJwePassword() { // Create the compact JWE: String jwe = Jwts.builder().setIssuer("me") // Optional work factor is specified in the header: - //.header().setPbes2Count(pbkdf2Iterations)).and() + //.header().pbes2Count(pbkdf2Iterations)).and() .encryptWith(password, alg, enc) .compact(); @@ -255,8 +255,8 @@ public void testExampleJwePassword() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleSecretJwk() { - SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 - SecretJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + SecretKey key = Jwts.SIG.HS512.key().build(); // or HS384 or HS256 + SecretJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -272,8 +272,8 @@ public void testExampleSecretJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleRsaPublicJwk() { - RSAPublicKey key = (RSAPublicKey) Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); - RsaPublicJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + RSAPublicKey key = (RSAPublicKey) Jwts.SIG.RS512.keyPair().build().getPublic(); + RsaPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -289,11 +289,11 @@ public void testExampleRsaPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleRsaPrivateJwk() { - KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.RS512.keyPair().build(); RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); - RsaPrivateJwk privJwk = builder().forKey(privKey).setIdFromThumbprint().build(); + RsaPrivateJwk privJwk = builder().key(privKey).idFromThumbprint().build(); RsaPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -312,8 +312,8 @@ public void testExampleRsaPrivateJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEcPublicJwk() { - ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); - EcPublicJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPair().build().getPublic(); + EcPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -329,11 +329,11 @@ public void testExampleEcPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEcPrivateJwk() { - KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.ES512.keyPair().build(); ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); - EcPrivateJwk privJwk = builder().forKey(privKey).setIdFromThumbprint().build(); + EcPrivateJwk privJwk = builder().key(privKey).idFromThumbprint().build(); EcPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -352,8 +352,8 @@ public void testExampleEcPrivateJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPublicJwk() { - PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); - OctetPublicJwk jwk = builder().forOctetKey(key).setIdFromThumbprint().build(); + PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); + OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -369,11 +369,11 @@ public void testExampleEdEcPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPrivateJwk() { - KeyPair pair = Jwts.SIG.Ed448.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); - OctetPrivateJwk privJwk = builder().forOctetKey(privKey).setIdFromThumbprint().build(); + OctetPrivateJwk privJwk = builder().octetKey(privKey).idFromThumbprint().build(); OctetPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString());