Skip to content

Files

Latest commit

 

History

History

tck

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Overview of the TCK

The MicroProfile JWT(MP-JWT) TCK consists of tests that validate the authentication and authorization of JAX-RS application endpoints secured using an MP-JWT authentication mechanism that both authenticates and authorizes access based on an MP-JWT token passed in via the HTTP Authorization header as a bearer token. There are 4 categories of unit tests in the base required TCK:

  1. Tests that validate the basic behavior of the MP-JWT JsonWebToken implementation independent of any JAX-RS application. Tests in this category are marked with the TestNG groups of "jwt" and "utils".

  2. Tests that validate the authentication and authorization of JAX-RS application endpoints secured using @RolesAllowed annotations. This includes testing the requirements for rejecting MP-JWT tokens. Tests in this category are marked with the TestNG group "jaxrs".

  3. Tests that validate the injection of o.e.m.j.ClaimValue, javax.json.JsonValue and javax.inject.Provider wrappers for the JsonWebToken claim values. Tests in this category are marked with the TestNG groups of "cdi", "cdi-json" and "cdi-provider".

  4. Tests that validate the use of the MicroProfile configuration feature to externalize the information necessariy to verify the MP-JWT signer and optional iss claim.

The TestNG testsuite for these categories of tests can be found in the tck directory src/test/resources/suites, file tck-base-suite.xml.

Optional Java EE Container Integration Tests

In addition to the categories of tests defined above, there are optional tests that illustrate the expected container API integration for Java EE container runtimes beyond JAX-RS. These tests are marked with the TestNG groups "ejb-optional", "jacc-optional", "servlet-optional" and "ee-security-optional". An MP-JWT implementation is not required to pass these tests in order to be considered a valid implementation.

The TestNG testsuite for these categories + the base categories of tests can be found in the tck directory src/test/resources/suites, file tck-full-suite.xml.

TCK Resource Files and Information

The TCK includes resources for the the MP-JWT token payload content as well as test issuer public and private RSA keys. These are used by the unit tests along with the org.eclipse.microprofile.jwt.tck.util.TokenUtils class to generate both valid and invalid tokens. A summary of the tck/resources directory contents is:

  • META-INF/microprofile-config-publickey.properties

    • A base MicroProfile config properties file for the org.eclipse.microprofile.jwt.tck.config.* package tests.

  • META-INF/microprofile-config-publickey-location.properties

    • A base MicroProfile config properties file for the org.eclipse.microprofile.jwt.tck.jaxrs.* package tests.

  • META-INF/microprofile-config-decryptionkey-location.properties

    • A base MicroProfile config properties file for the org.eclipse.microprofile.jwt.tck.jaxrs.jwe.* package tests.

  • jwt-content1.json

  • testJWTCallerPrincipal.json

  • usePreferredName.json

  • useSubject.json

    • Used by the TokenUtilsTest to validate the MP-JWT implementation under test JsonWebToken implementation.

  • Token1.json

  • Token2.json

    • Used by the various JAX-RS and CDI tests

  • privateKey.pem

    • The test issuer RSA private key used to sign the MP-JWT tokens generated by the org.eclipse.microprofile.jwt.tck.container.jaxrs.* package tests.

  • ecPrivateKey.pem

    • The test issuer EllipticCurve private key used to sign the MP-JWT tokens generated by the org.eclipse.microprofile.jwt.tck.container.jaxrs.* package tests.

  • privateKey4k.pem

    • The test issuer RSA private key used to sign the MP-JWT tokens generated by the org.eclipse.microprofile.jwt.tck.config.* package tests.

  • publicKey.pem

    • The test issuer RSA public key that MP-JWT implementations under test use to validate the token signature in the org.eclipse.microprofile.jwt.tck.container.jaxrs.* package tests.

  • ecPublicKey.pem

    • The test issuer RSA public key that MP-JWT implementations under test use to validate the token signature in the org.eclipse.microprofile.jwt.tck.container.jaxrs.* package tests.

  • publicKey4k.pem

    • The test issuer EllipticCurve public key that MP-JWT implementations under test use to validate the token signature in the org.eclipse.microprofile.jwt.tck.config.* package tests.

  • RequiredClaims.json

    • Used by the RequiredClaimsTest to generate a MP-JWT with the minimum required claims.

  • TokenBadIss.json

    • Used by the IssNoValidationBadIssTest to validate that the iss claim is ignored when validation is disabled.

  • signer-key4k.jwk

    • A JWK representation of the signer RSA public key used by some of the org.eclipse.microprofile.jwt.tck.config.* package tests.

  • signer-keyset4k.jwk

    • A JWKS representation of the signer RSA public key used by some of the org.eclipse.microprofile.jwt.tck.config.* package tests.

  • encryptorPublicKey.jwk

    • A JWK representation of the encryptor RSA public key used by some of the org.eclipse.microprofile.jwt.tck.config.jwe.* package tests.

  • decryptorPrivateKey.jwk

    • A JWK representation of the decryptor RSA private key used by some of the org.eclipse.microprofile.jwt.tck.config.jwe.* package tests.

  • * decryptorPrivateKeySet.jwk

    • A JWKS representation of the decryptor RSA private key used by some of the org.eclipse.microprofile.jwt.tck.config.jwe.* package tests.

The test issuer value used in all valid test MP-JWT tokens as the iss claim value is "https://server.example.com".

The test issuer public key is the tck/resources/publicKey.pem file. It is included in every test WebArchive artifact as an archive classpath resource at the location /WEB-INF/classes/publicKey.pem.

The generated test JWT has its exp, iat and auth_time claims are set to the current time when the token is generated, as the number of seconds from 1970-01-01T00:00:00Z UTC.

An example of how this information can be used to verify a JWT using the Jose4j library used by the TCK to generate the test JWTs can be found in the org.eclipse.microprofile.jwt.tck.utils.TokenUtilsTest#validateToken method.

=Running the MicroProfile JWT Auth TCK

The TCK is designed around a set of Arquillian based unit tests that require the MP-JWT implementation under test to provide a TCK harness artifact that provides an org.jboss.arquillian.core.spi.LoadableExtension that installs a org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor to augment the base org.jboss.shrinkwrap.api.spec.WebArchive with the implementation specific artifacts, descriptors, libraries, etc. needed for the implementation to properly deploy the test web archive.

There are base implementations of the LoadableExtension and ApplicationArchiveProcessor that can be used for straight-forward augmentation scenarios, but you can always provide your own implementations. An example of the former is: https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck-viabase

while an example of the latter is: https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck

Creating Your Implementation TCK Harness Artifact

As described, you need to create an artifact that bundles a LoadableExtension using a Java ServiceProvider that installs an ApplicationArchiveProcessor that augments the base TCK test web application archive with the implementation specific configuration and dependencies needed to successfully deploy and test the web application with MP-JWT authentication enabled.

An example skeleton pom.xml is shown here:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>my.groupID</groupId>
    <artifactId>jwt-auth-tck</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>MicroProfile JWT Auth TCK Harness MyCoolMP Implementation</name>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <version.wildfly.swarm>2017.7.0</version.wildfly.swarm>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>1.1.13.Final</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- This is the MP-JWT TCK base extension and utility classes -->(1)
        <dependency>
            <groupId>org.eclipse.microprofile.jwt</groupId>
            <artifactId>microprofile-jwt-auth-tck</artifactId>
            <version>2.0</version>
        </dependency>
        <!-- This is the actual MP-JWT TCK test classes -->(2)
        <dependency>
            <groupId>org.eclipse.microprofile.jwt</groupId>
            <artifactId>microprofile-jwt-auth-tck</artifactId>
            <version>2.0</version>
            <type>test-jar</type>
            <scope>test</scope>
        </dependency>
        <!-- Arquillian extension SPI -->(3)
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-container-spi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-container-test-spi</artifactId>
        </dependency>
        <!-- You need to specify your JAX-RS client implementation as the unit
        tests make use of that API, but do not specify the implementation.
        -->(4)
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <version>3.1.1.Final</version>
        </dependency>

        <!-- Specify your container runtime arquillian integration and dependencies -->
        <dependency>(5)
            <groupId>MY_GROUP</groupId>
            <artifactId>arquillian-container</artifactId>
            <version>${container-version}</version>
        </dependency>
        ...
    </dependencies>

...

</project>
  1. org.eclipse.microprofile.jwt:microprofile-jwt-auth-tck is the MP-JWT artifact that contains the base LoadableExtension and ApplicationArchiveProcessor classes and TokenUtils class.

  2. org.eclipse.microprofile.jwt:microprofile-jwt-auth-tck type=test-jar is the MP-JWT TCK tests themselves you need to run for the TCK. You would only need this if you are running the TCK from within your TCK harness project.

  3. The 2 indicated Arquillian extension SPI dependencies provide the LoadableExtension and ApplicationArchiveProcessor interfaces and dependent classes.

  4. The TCK unit tests make use of the JAX-RS client API, but does not provide an implementation, so your TCK harness artifact must specify what implementation to use. Here the Resteasy implementation is being specified.

  5. Lastly, you must specify the property Arquillian container runtime that is approriate for you MP-JWT implementation, along with whatever container runtime dependencies are required.

What Your TCK Harness Needs to Configure

The primary elements that need to be configured in the MP-JWT runtime are the security domain settings. This will entail the installation of the MP-JWT authentication mechanism, the token validation settings, and a group to role mapping.

Role Mapping

Some tests in the "ee-security-optional" group require a mapping from a group name in the "groups" claim of the MP-JWT token to a custom role name used in an endpoint @RolesAllowed statement. The following table lists the group names and the role mappings that are expected in the TCK unit tests. This includes the required one-to-one mapping of the group name:

Echoer

Echoer

Tester

Tester

Token2Role

Token2Role

group1

group1, Group1MappedRole

An example of how a TCK harness implementation that is based on Glassfish might perform the group1 required mappings via is shown in the following glassfish-web.xml descriptor that the TCK harness would add to the test WebArchive in it’s ApplicationArchiveProcessor:

<glassfish-web-app>
    ...
    <security-role-mapping>
        <role-name>group1</role-name>
        <group-name>group1</group-name>
    </security-role-mapping>

    <security-role-mapping>
        <role-name>group1</role-name>
        <group-name>Group1MappedRole</group-name>
    </security-role-mapping>
    ...
</glassfish-web-app>

Equivalent Security Constraints

This section describes the equivalent web.xml style of security constraints that are expected for the various TCK deployments.

ClaimValueInjectionTest
  • url-pattern: /endp/*

  • role-name: Echoer

  • role-name: Tester

InvalidTokenTest
  • url-pattern: /endp/*

  • role-name: Echoer

JsonValueInjectionTest
  • url-pattern: /endp/*

  • role-name: Echoer

  • role-name: Tester

ProviderValueInjectionTest
  • url-pattern: /endp/*

  • role-name: Echoer

  • role-name: Tester

RequiredClaimsEndpoint
  • url-pattern: /endp/*

  • role-name: Tester

RolesAllowedTest
  • url-pattern: /endp/echo

  • role-name: Echoer

  • url-pattern: /endp/echo2

  • role-name: NoSuchUser - This role is not granted to any test token

  • url-pattern/endp/getPrincipalClass

  • url-pattern/endp/checkIsUserInRole

  • url-pattern/endp/getInjectedPrincipal

  • role-name: Echoer

  • url-pattern: /endp/needsGroup1Mapping

  • role-name: Group1MappedRole - This role needs to be mapped to the token group1 group

  • url-pattern/endp/echoNeedsToken2Role

  • role-name: Token2Role

UnsecuredPingTest

No authentication required

Information Available to the Harness ApplicationArchiveProcessor

The TCK harness ApplicationArchiveProcessor implementation has access to information added to the archive during the deployment creation. Some of the key items are shown by this implementation fragment:

public class WFSwarmWarArchiveProcessor implements ApplicationArchiveProcessor {
    private static Logger log = Logger.getLogger(WFSwarmWarArchiveProcessor.class.getName());

    @Override
    public void process(Archive<?> appArchive, TestClass testClass) {
        if (!(appArchive instanceof WebArchive)) {
            return;
        }
        WebArchive war = WebArchive.class.cast(appArchive);
        Node configProps = war.get("/META-INF/microprofile-config.properties");(1)
        Node publicKeyNode = war.get("/WEB-INF/classes/publicKey.pem");(2)
        Node publicKey4kNode = war.get("/WEB-INF/classes/publicKey4k.pem");(3)
        Node mpJWT = war.get("MP-JWT");(4)
        Node testVersionNode = war.get(MpJwtTestVersion.VERSION_LOCATION);(5)
        MpJwtTestVersion testVersion = MpJwtTestVersion.MPJWT_V_1_0;
        if(testVersionNode != null) {
            String content = readAsset(testVersionNode);
            testVersion = MpJwtTestVersion.valueOf(content);
        }
  1. The optional microprofile-config.properties. Only the config related tests currently have this asset.

  2. The optional public key content of the token signer.

  3. The optional 4096 bit public key content of the token signer.

  4. The optional base64 encoded string of the MP-JWT that will be passed by the test. Currently only the Iss*Validation* tests pass this in.

  5. A marker resource used to indicate the version of MP-JWT the test is targeting. It will be the string value of one of the MpJwtTestVersion enums. The absense of a marker should be treated as an MP-JWT 1.0 test as shown. For MpJwtTestVersion.MPJWT_V_1_0, there will be no bundled META-INF/microprofile-config.properties, and so your harness should set any vendor specific defaults such as the signer public key.

You can use this information to set vendor specific settings that are need to support proper operation of your MP-JWT implementation.

Running Your Implementation With the TCK

Once you have built and installed your TCK harness artifact, you can run the TCK tests against it by using either the tokens-se or container profiles.

container Profile

The container profile is a test of JAX-RS client tests that validate a JAX-RS endpoint bundled in a WebArchive deployment via your implementation. These tests require Arquillian container runtime integration to properly deploy and start your container. You typically provide this via a dependency on an arquillian container artificat, for example, Tomcat based containers might include a dependency like:

<dependency>
  <groupId>org.jboss.arquillian.container</groupId>
  <artifactId>arquillian-tomcat-embedded-7</artifactId>
  <version>1.0.0</version>
  <scope>test</scope>
</dependency>

This test of tests also require the org.jboss.arquillian.core.spi.LoadableExtension and org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor implementations as discussed above.

To run this set of tests, issue the following command from within the microprofile-jwt-auth/tck directory:

mvn -Pcontainer -Dtck.container.groupId={MY_GROUP} -Dtck.container.artifactId={MY_ARTIFACT} -Dtck.container.version={MY_VERSION} test

where you would replace the {MY_GROUP}, {MY_ARTIFACT} and {MY_VERSION} with the <groupId>…​<groupId>, <artifactId>…​</artifactId>, and <version>…​</version> respectively from your TCK harness artifact.

A concrete example is for running with the TCK harness artifiact from the https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck project is:

mvn -Pcontainer -Dtck.container.groupId=org.wildfly.swarm -Dtck.container.artifactId=jwt-auth-tck -Dtck.container.version=1.0-SNAPSHOT

Running the TCK Tests in Your Build

You can run the TCK tests from within your TCK harness build by including the following in your pom.xml:

    <dependencies>
    ...
        <!-- Include the MP-JWT TCK dependencies, utility and base classes + actual test classes -->
        <dependency>
            <groupId>org.eclipse.microprofile.jwt</groupId>
            <artifactId>microprofile-jwt-auth-tck</artifactId>
            <version>2.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.microprofile.jwt</groupId>
            <artifactId>microprofile-jwt-auth-tck</artifactId>
            <version>2.0</version>
            <type>test-jar</type>
            <scope>test</scope>
        </dependency>
        <!-- You need to add a dependency for a JAX-RS client implementation -->
        <dependency>
            <groupId>FIXME</groupId>
            <artifactId>some-jaxrs-client-impl</artifactId>
            <version>x.y</version>
            <scope>test</scope>
        </dependency>
        <!-- Your additional container dependences... -->
    </dependencies>

    <build>
        <plugins>
        ...
            <!-- Run the TCK tests aginst the tck-base-suite.xml -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <redirectTestOutputToFile>true</redirectTestOutputToFile>
                    <suiteXmlFiles>
                        <suiteXmlFile>${project.build.directory}/tck-suite/suites/tck-base-suite.xml</suiteXmlFile>
                    </suiteXmlFiles>
                    <forkCount>1</forkCount>
                </configuration>
            </plugin>

            <!-- Extract the TCK Suite Files -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack</id>
                        <phase>process-test-classes</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.eclipse.microprofile.jwt</groupId>
                                    <artifactId>microprofile-jwt-auth-tck</artifactId>
                                    <version>2.0</version>
                                    <type>test-jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/tck-suite</outputDirectory>
                                    <!-- Includes the tck-base-suite.xml file -->
                                    <includes>**/tck-build-suite.xml</includes>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Alternatively, you can copy any of the TCK suite files present in src/test/resources/suites to your project and customize to fit your needs. If this is the case, you can remove the maven-dependency-plugin section from the previous XML fragment.

You then simply run mvn test to run the TCK tests. An example of using this approach can be found in the https://github.com/MicroProfileJWT/wfswarm-jwt-auth-tck repo. Running

[wfswarm-jwt-auth-tck 664]$ mvn -Dswarm.resolver.offline=true test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building MicroProfile JWT Auth TCK Harness WFSwarm Implementation 1.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jwt-auth-tck ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 6 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ jwt-auth-tck ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ jwt-auth-tck ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/starksm/Dev/JBoss/Microprofile/wfswarm-jwt-auth-tck/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ jwt-auth-tck ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.20:test (default-test) @ jwt-auth-tck ---
[INFO] No tests to run.
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[INFO] Tests run: 116, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 469.176 s - in TestSuite
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 116, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 07:51 min
[INFO] Finished at: 2018-05-25T23:10:16-07:00
[INFO] Final Memory: 73M/909M
[INFO] ------------------------------------------------------------------------

TCK System Properties

There is one system property that may need to be set in order for the tests that attempt to load a public key from a JWKS URL:

  • mp.jwt.tck.jwks.baseURL : Set to the location of your container JAX-RS root. This defaults to "http://localhost:8080/", so it is only necessary to set this property if that default does not match your container’s default.

For example,

mvn -Pcontainer -Dmp.jwt.tck.jwks.baseURL=http://jwks-host:9090/ -Dtck.container.groupId=org.wildfly.swarm -Dtck.container.artifactId=jwt-auth-tck -Dtck.container.version=1.0-SNAPSHOT