Skip to content

Commit 1739c88

Browse files
authored
Merge pull request #23 from MicroProfileJWT/master
TCK and documentation updates
2 parents 6c50e6e + 5a29af1 commit 1739c88

23 files changed

+1464
-194
lines changed

api/src/main/java/org/eclipse/microprofile/jwt/Claim.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import java.lang.annotation.Target;
2727

2828
/**
29-
* Annotation used to signify and injection point for a {@link ClaimValue} from
29+
* Annotation used to signify an injection point for a {@link ClaimValue} from
3030
* a {@link JsonWebToken}
3131
*/
3232
@Qualifier

pom.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
<dependencies>
9696
<dependency>
9797
<groupId>javax</groupId>
98-
<artifactId>javaee-web-api</artifactId>
98+
<artifactId>javaee-api</artifactId>
9999
<type>pom</type>
100100
<version>7.0</version>
101101
<scope>import</scope>
@@ -137,6 +137,13 @@
137137
<groupId>org.apache.maven.plugins</groupId>
138138
<artifactId>maven-jar-plugin</artifactId>
139139
<version>3.0.2</version>
140+
<executions>
141+
<execution>
142+
<goals>
143+
<goal>test-jar</goal>
144+
</goals>
145+
</execution>
146+
</executions>
140147
</plugin>
141148
</plugins>
142149
</pluginManagement>

spec/src/main/asciidoc/interoperability.asciidoc

Lines changed: 112 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@
1717

1818
## Recommendations for Interoperability
1919

20-
The decision about using MicroProfile JWT(MP-JWT) as a token format depends on the agreement between both identity
20+
The maximum utility of the MicroProfile JWT(MP-JWT) as a token format depends on the agreement between both identity
2121
providers and service providers. This means identity providers - responsible for issuing tokens - should be able to
22-
issue tokens using the JWT format in a way that service providers can understand in order to introspect the token and
22+
issue tokens using the MP-JWT format in a way that service providers can understand in order to introspect the token and
2323
gather information about a subject. To that end, the requirements for the MicroProfile JWT are:
2424

25-
1. An authentication token.
26-
2. An authorization token that contains Java EE application level roles indirectly granted via groups.
25+
1. Be usable as an authentication token.
26+
2. Be usable as an authorization token that contains Java EE application level roles indirectly granted via a groups claim.
2727
3. Can be mapped to IdentityStore in JSR375.
2828
4. Can support additional standard claims described in https://www.iana.org/assignments/jwt/jwt.xhtml as
2929
well as non-standard claims.
3030
3131
To meet those requirements, we introduce 2 new claims to the MP-JWT:
3232

33-
* "upn": A human readable claim that uniquely identifies the subject or user principal of token, across
33+
* "upn": A human readable claim that uniquely identifies the subject or user principal of the token, across
3434
the MicroProfile services the token will be accessed with.
35-
* "groups": The token subject's group membership that will be mapped to Java EE application
36-
level roles.
35+
* "groups": The token subject's group memberships that will be mapped to Java EE style application
36+
level roles in the MicroProfile service container.
3737
38-
### Required Claims
38+
### Minimum MMP-JWT Required Claims
3939
The required minimum set of MP-JWT claims is then:
4040

4141
typ:: This JOSE header parameter identifies the token as an RFC7519 and must be "JWT" https://tools.ietf.org/html/rfc7519#section-5.1[RFC7519, Section 5.1]
@@ -373,7 +373,7 @@ integration is with the JAX-RS container, and injection of the MP-JWT types.
373373

374374
#### Injection of `JsonWebToken`
375375
An MP-JWT implementation must support the injection of the currently authenticated
376-
caller as a JsonWebToken with @RequestScoped:
376+
caller as a JsonWebToken with @RequestScoped scope:
377377

378378
```java
379379
@Path("/endp")
@@ -388,12 +388,65 @@ public class RolesEndpoint {
388388
#### Injection of `ClaimValue`
389389

390390
This specification requires support for injection of claims from the current
391-
`JsonWebToken` using the `org.eclipse.microprofile.jwt.@Claim` qualifier and
392-
`org.eclipse.microprofile.jwt.ClaimValue` interface with with @RequestScoped scoping.
393-
The following example code fragment illustrates various examples of injecting
394-
different types of claims using a range of generic forms of the `ClaimValue`:
391+
`JsonWebToken` using the `org.eclipse.microprofile.jwt.Claim` qualifier:
392+
393+
[source,java]
394+
----
395+
/**
396+
* Annotation used to signify an injection point for a {@link ClaimValue} from
397+
* a {@link JsonWebToken}
398+
*/
399+
@Qualifier
400+
@Retention(RetentionPolicy.RUNTIME)
401+
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
402+
public @interface Claim {
403+
/**
404+
* The value specifies the id name the claim to inject
405+
* @return the claim name
406+
* @see JsonWebToken#getClaim(String)
407+
*/
408+
String value() default "";
395409
396-
```java
410+
/**
411+
* An alternate way of specifying a claim name using the {@linkplain Claims}
412+
* enum
413+
* @return the claim enum
414+
*/
415+
Claims standard() default Claims.UNKNOWN;
416+
417+
}
418+
----
419+
420+
and `org.eclipse.microprofile.jwt.ClaimValue` interface:
421+
[source,java]
422+
----
423+
/**
424+
* A representation of a claim in a {@link JsonWebToken}
425+
* @param <T> the expected type of the claim
426+
*/
427+
public interface ClaimValue<T> extends Principal {
428+
429+
/**
430+
* Access the name of the claim.
431+
* @return The name of the claim as seen in the JsonWebToken content
432+
*/
433+
@Override
434+
public String getName();
435+
436+
/**
437+
* Access the value of the claim.
438+
* @return the value of the claim.
439+
*/
440+
public T getValue();
441+
}
442+
----
443+
444+
with @RequestScoped scoping. The following example code fragment illustrates various
445+
examples of injecting different types of claims using a range of generic forms of
446+
the `ClaimValue`:
447+
448+
[source,java]
449+
----
397450
import org.eclipse.microprofile.jwt.Claim;
398451
import org.eclipse.microprofile.jwt.ClaimValue;
399452
import org.eclipse.microprofile.jwt.Claims;
@@ -403,7 +456,7 @@ import org.eclipse.microprofile.jwt.Claims;
403456
public class RolesEndpoint {
404457
...
405458
406-
@Inject
459+
@Inject // <1>
407460
@Claim(standard = Claims.raw_token)
408461
private ClaimValue<String> rawToken;
409462
@Inject
@@ -412,20 +465,20 @@ public class RolesEndpoint {
412465
@Inject
413466
@Claim(standard = Claims.jti)
414467
private ClaimValue<String> jti;
415-
@Inject
468+
@Inject // <2>
416469
@Claim("jti")
417470
private ClaimValue<Optional<String>> optJTI;
418471
@Inject
419472
@Claim("jti")
420473
private ClaimValue objJTI;
421-
@Inject
474+
@Inject // <3>
422475
@Claim("aud")
423476
private ClaimValue<Set<String>> aud;
424477
@Inject
425478
@Claim("groups")
426479
private ClaimValue<Set<String>> groups;
427-
@Inject
428-
@Claim("iat")
480+
@Inject // <4>
481+
@Claim(standard=Claims.iat)
429482
private ClaimValue<Long> issuedAt;
430483
@Inject
431484
@Claim("iat")
@@ -436,23 +489,58 @@ public class RolesEndpoint {
436489
@Inject
437490
@Claim("auth_time")
438491
private ClaimValue<Optional<Long>> authTime;
439-
@Inject
492+
@Inject // <5>
440493
@Claim("custom-missing")
441494
private ClaimValue<Optional<Long>> custom;
442-
```
495+
----
496+
<1> Injection of the raw MP-JWT token string.
497+
<2> Injection of the jti token id as an `Optional<String>` wapper.
498+
<3> Injection of the aud audience claim as a Set<String>. This is the required
499+
type as seen by looking at the Claims.aud enum value's Java type member.
500+
<4> Injection of the issued at time claim using an @Claim that references the
501+
claim name using the Claims.iat enum value.
502+
<5> Injection of a custom claim that does exist will result in an Optional<Long>
503+
value for which isPresent() will return false.
443504

444505
The example shows that one may specify the name of the claim using with a
445-
string or a Claims enum value. The string form would allow for specifying non-standard
446-
claims while the Claims enum approach guards against typos and misspellings.
506+
string or a `Claims` enum value. The string form would allow for specifying non-standard
507+
claims while the `Claims` enum approach guards against typos and mis-spellings.
447508

448509
The `@RequestScoped` requirement does introduce some additional complexity for
449510
a CDI extension as a producer method cannot have the
450511
`javax.enterprise.inject.spi.InjectionPoint` provided as a parameter to allow
451512
for distinguishing type. This requires that the CDI extension collect the `ClaimValue`
452-
injection sites by @Claim value and `ClaimValue` type. An example of one way
513+
injection sites by `@Claim` value and `ClaimValue` type. An example of one way
453514
to accomplish this via dynamic producer methods is shown in this prototype
454515
extension: https://github.com/MicroProfileJWT/microprofile-jwt-auth-wfswarm/blob/master/src/main/java/org/eclipse/microprofile/jwt/wfswarm/cdi/MPJWTExtension.java[MPJWTExtension].
455516

517+
#### Injection of Claim Values using `javax.inject.Provider<?>`
518+
An MP-JWT implementation is required to support injection of the currently
519+
authenticated `JsonWebToken` claim values using the `javax.inject.Provider<?>`
520+
wrapper as the injection site type as shown in this code fragment:
521+
522+
[source,java]
523+
----
524+
@Path("/endp")
525+
@ApplicationScoped
526+
public class RolesEndpoint {
527+
...
528+
529+
@Inject
530+
@Claim(standard = Claims.jti)
531+
private Provider<String> providerJTI;
532+
@Inject
533+
@Claim(standard = Claims.iat)
534+
private Provider<Long> providerIAT;
535+
@Inject
536+
@Claim("groups")
537+
private Provider<Set<String>> providerGroups;
538+
----
539+
540+
### JAX-RS Container API Integration
541+
The behavior of the following JAX-RS security related methods is required for
542+
MP-JWT implementations.
543+
456544
#### `javax.ws.rs.core.SecurityContext.getUserPrincipal()`
457545
The `java.security.Principal` returned from these methods MUST be an instance of `org.eclipse.microprofile.jwt.JsonWebToken`.
458546

spec/src/main/asciidoc/microprofile-jwt-auth-spec.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
= Interoperable JWT RBAC for Microprofile
1919
:author: Scott Stark; Pedro Igor Silva
2020
21-
:revnumber: 0.2 Draft
22-
:revdate: 2017-07-27
21+
:revnumber: 1.0 Draft
22+
:revdate: 2017-08-23
2323
:revremark: Proposal
2424
:version-label!:
2525
:sectanchors:

tck/pom.xml

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030

3131
<properties>
3232
<version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers>
33+
<version.testng>6.10</version.testng>
3334
<checkstyle.methodNameFormat>^_?[a-z][a-zA-Z0-9_]*$</checkstyle.methodNameFormat>
3435
<!-- TCK properties that must be overriden in the vendor profile -->
3536
<tck.ITokenParserArtifact>INVALID</tck.ITokenParserArtifact>
3637
<tck.includes>INVALID</tck.includes>
38+
<tck.testSuite>tck-null-suite.xml</tck.testSuite>
3739
</properties>
3840

3941
<dependencies>
@@ -66,6 +68,19 @@
6668
<version>1.2</version>
6769
<scope>provided</scope>
6870
</dependency>
71+
<dependency>
72+
<groupId>javax.security.jacc</groupId>
73+
<artifactId>javax.security.jacc-api</artifactId>
74+
<version>1.5</version>
75+
<scope>provided</scope>
76+
<optional>true</optional>
77+
</dependency>
78+
<dependency>
79+
<groupId>javax.ejb</groupId>
80+
<artifactId>ejb-api</artifactId>
81+
<version>3.0</version>
82+
<scope>provided</scope>
83+
</dependency>
6984
<dependency>
7085
<groupId>com.nimbusds</groupId>
7186
<artifactId>nimbus-jose-jwt</artifactId>
@@ -77,10 +92,9 @@
7792
</dependency>
7893

7994
<dependency>
80-
<groupId>junit</groupId>
81-
<artifactId>junit</artifactId>
82-
<version>4.12</version>
83-
<scope>test</scope>
95+
<groupId>org.testng</groupId>
96+
<artifactId>testng</artifactId>
97+
<version>${version.testng}</version>
8498
</dependency>
8599
<dependency>
86100
<groupId>org.jboss.arquillian.container</groupId>
@@ -91,15 +105,13 @@
91105
<artifactId>arquillian-container-test-spi</artifactId>
92106
</dependency>
93107
<dependency>
94-
<groupId>org.jboss.arquillian.junit</groupId>
95-
<artifactId>arquillian-junit-container</artifactId>
96-
<scope>test</scope>
108+
<groupId>org.jboss.arquillian.testng</groupId>
109+
<artifactId>arquillian-testng-container</artifactId>
97110
</dependency>
98111
<dependency>
99112
<groupId>org.jboss.shrinkwrap.resolver</groupId>
100113
<artifactId>shrinkwrap-resolver-depchain</artifactId>
101114
<version>${version.shrinkwrap.resolvers}</version>
102-
<scope>test</scope>
103115
<type>pom</type>
104116
</dependency>
105117
</dependencies>
@@ -112,15 +124,17 @@
112124
<artifactId>maven-surefire-plugin</artifactId>
113125
<version>2.20</version>
114126
<configuration>
115-
<includes>
116-
<include>${tck.includes}</include>
117-
</includes>
118-
<forkCount>1</forkCount>
127+
<redirectTestOutputToFile>true</redirectTestOutputToFile>
128+
<suiteXmlFiles>
129+
<suiteXmlFile>${tck.testSuite}</suiteXmlFile>
130+
</suiteXmlFiles>
131+
<environmentVariables>
132+
</environmentVariables>
119133
<systemPropertyVariables>
120-
<tck.ITokenParserArtifact>${tck.ITokenParserArtifact}</tck.ITokenParserArtifact>
121-
<buildDirectory>${project.build.directory}</buildDirectory>
122134
</systemPropertyVariables>
123-
135+
<forkCount>1</forkCount>
136+
<reuseForks>true</reuseForks>
137+
<trimStackTrace>false</trimStackTrace>
124138
</configuration>
125139
</plugin>
126140
</plugins>
@@ -155,8 +169,26 @@
155169
<profile>
156170
<id>container</id>
157171
<properties>
158-
<!-- Include all tests under the org.eclipse.microprofile.jwt.tck.container package -->
159-
<tck.includes>**/container/**/*Test.java</tck.includes>
172+
<tck.testSuite>tck-base-suite.xml</tck.testSuite>
173+
</properties>
174+
<dependencies>
175+
<dependency>
176+
<!--
177+
These need to be specified as system properties on mvn command line:
178+
mvn -Pcontainer -Dtck.container.groupId=org.wildfly.swarm -Dtck.container.artifactId=jwt-auth-tck \
179+
-Dtck.container.version=1.0-SNAPSHOT test
180+
-->
181+
<groupId>${tck.container.groupId}</groupId>
182+
<artifactId>${tck.container.artifactId}</artifactId>
183+
<version>${tck.container.version}</version>
184+
<scope>test</scope>
185+
</dependency>
186+
</dependencies>
187+
</profile>
188+
<profile>
189+
<id>container-full</id>
190+
<properties>
191+
<tck.testSuite>tck-full-suite.xml</tck.testSuite>
160192
</properties>
161193
<dependencies>
162194
<dependency>

0 commit comments

Comments
 (0)