A simple way to test your oauth2 server is to use TomEE Embedded JUnit runner. It needs an application which defines the test, and it is simple for us. It defines that we need a random port (the runner will automatically deploy the classpath):

@Application
public class App {
   public static final String CLIENT_ID = "client";
   public static final String CLIENT_SECRET = "secret";

   @RandomPort("http")
   private URL base;
}

Then we need a client to be able to do an authentication request so we will persist it in an CDI bean observing a startup event (addClient()). This bean will also setup jaas for tests providing the absolute path of our jaas configuration file (setJaas()):

@Dependent // test doesnt have a beans.xml
public final class Init {
   @PersistenceContext
   private EntityManager em;

   @Resource
   private UserTransaction ut;

   void init(@Observes @Initialized(ApplicationScoped.class) final Object start) throws Throwable {
       addClient();
       setJaas();
   }

   private void setJaas() {
       System.setProperty("java.security.auth.login.config", new File(jarLocation(App.class), "oauth2.jaas").getAbsolutePath());
   }

   private void addClient() throws NotSupportedException, SystemException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
       final ClientEntity entity = new ClientEntity();
       entity.setId(CLIENT_ID);
       entity.setSecret(CLIENT_SECRET);
       entity.setConfidential(true);
       ut.begin();
       em.persist(entity);
       ut.commit();
   }
}

Finally, we will define a test, getting a token and refreshing it:

@RunWith(TomEEEmbeddedSingleRunner.class)
public class OAuth2Test {
   @RandomPort("http")
   private URL base;

   @Inject
   private OAuthDataProvider provider;

   @Test
   public void token() {
       final Invocation.Builder request = ClientBuilder.newClient()
               .target(base.toExternalForm())
               .path("api/token")
               .request(MediaType.APPLICATION_JSON_TYPE);

       // get a token
       final ClientAccessToken token = request
               .post(Entity.entity(new Form()
  .param(OAuthConstants.RESOURCE_OWNER_NAME, "test")
  .param(OAuthConstants.RESOURCE_OWNER_PASSWORD, "pwd")
  .param(OAuthConstants.CLIENT_ID, App.CLIENT_ID)
  .param(OAuthConstants.CLIENT_SECRET, App.CLIENT_SECRET)
  .param(OAuthConstants.GRANT_TYPE, OAuthConstants.RESOURCE_OWNER_GRANT),
                       MediaType.APPLICATION_FORM_URLENCODED_TYPE), ClientAccessToken.class);
       validateToken(token);

       // refresh the token
       final ClientAccessToken refreshedToken = request.post(Entity.entity(new Form()
  .param(OAuthConstants.REFRESH_TOKEN, token.getRefreshToken())
  .param(OAuthConstants.RESOURCE_OWNER_PASSWORD, "pwd")
  .param(OAuthConstants.CLIENT_ID, App.CLIENT_ID)
  .param(OAuthConstants.CLIENT_SECRET, App.CLIENT_SECRET)
  .param(OAuthConstants.GRANT_TYPE, OAuthConstants.REFRESH_TOKEN_GRANT), MediaType.APPLICATION_FORM_URLENCODED_TYPE),
               ClientAccessToken.class);
       validateToken(refreshedToken);
       validateToken(token); // still valid
   }

   private void validateToken(final ClientAccessToken token) {
       assertNotNull(token.getTokenKey());
       assertNotNull(token.getRefreshToken());

       final ServerAccessToken found = provider.getAccessToken(token.getTokenKey());
       assertNotNull(found);
       assertFalse(OAuthUtils.isExpired(found.getIssuedAt(), 3600L));
   }
}

Bonus: fat jar

Using TomEE Embedded is easy to bundle this server as a jar. You can reuse tomee embedded main but since we need few parameters we can force, I will redefine it as below:

public final class OAuth2 {
   public static void main(final String[] args) {
       Main.main(new String[] {
          "--as-war", "--single-classloader"
       });
   }
}

Tip: TomEE 7.0.2 will provide this main as part of TomEE distribution (org.apache.tomee.embedded.FatApp). You can also desire to handle args forwarding to tomee-embedded main, if you need more control over the deployment like server.xml location for instance.

This will simply deploy the jar as a war and avoid a webapp classloader (i.e. it will reuse the JVM classloader in this case).

Then your pom will look like (click on the link for the complete version, here is a simplified one for the blog):

<?xml version="1.0" encoding="UTF-8"?>
<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>

  <!-- simplified -->

 <dependencies>
   <dependency>
     <groupId>org.apache.tomee</groupId>
     <artifactId>javaee-api</artifactId>
     <version>7.0</version>
     <scope>provided</scope>
   </dependency>

   <dependency>
     <groupId>org.apache.tomee</groupId>
     <artifactId>tomee-embedded</artifactId>
     <version>7.0.1</version>   </dependency>
   <dependency>
     <groupId>org.apache.cxf</groupId>
     <artifactId>cxf-rt-rs-security-oauth2</artifactId>
     <version>3.1.6</version>
   </dependency>
 </dependencies>

 <build>
   <plugins>
     <plugin>
       <groupId>org.apache.openjpa</groupId>
       <artifactId>openjpa-maven-plugin</artifactId>
       <version>2.4.1</version>
       <configuration>
         <includes>**/entity/*.class</includes>
       </configuration>
     </plugin>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-shade-plugin</artifactId>
       <version>2.4</version>
       <executions>
         <execution>
           <phase>package</phase>
           <goals>
             <goal>shade</goal>
           </goals>
           <configuration>
             <dependencyReducedPomLocation>${project.build.directory}/reduced-pom.xml</dependencyReducedPomLocation>
             <transformers>
               <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                 <mainClass>com.github.rmannibucau.oauth2.runner.OAuth2</mainClass>
               </transformer>
               <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                 <resource>META-INF/cxf/bus-extensions.txt</resource>
               </transformer>
               <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                 <resource>META-INF/openwebbeans/openwebbeans.properties</resource>
               </transformer>
             </transformers>
             <filters>
               <filter>
                 <artifact>*:*</artifact>
                 <excludes>
                   <exclude>META-INF/faces-config.xml</exclude>
                 </excludes>
               </filter>
             </filters>
           </configuration>
         </execution>
       </executions>
     </plugin>
   </plugins>
 </build>
</project>

Points to note are:

  • Openjpa plugin to enhance entities if you rely on OpenJPA as JPA provider to avoid surprises at runtime

  • The shade plugin defines our OAuth2 main as mainClass

  • We merge cxf-extensions.txt on one side and openwebbeans.properties on the other side files during the shade to not lose any configuration of both libraries

  • We exclude tomee faces-config.xml because we don’t need JSF in this project

And that’s it! Run mvn package and in target you will get a OAuth2 server runnable with java -jar simple-oauth2-1.0-SNAPSHOT.jar!

Tip: as we used JPA for the persistence, you may need to define a datasource. And as it is TomEE you can do it using system properties:

 

java -jar simple-oauth2-1.0-SNAPSHOT.jar
    -Dds=new://Resource?type=DataSource
    -Dds.JdbcUrl=jdbc:mysql://localhost:3306/oauth2
    -Dds.JdbcDriver=com.mysql.jdbc.Driver
    -Dds.UserName=oauth2
    -Dds.Password=xsdgedugede=
    -Dds.PasswordCipher=crypto

Conclusion

CXF provides much more oauth2 features, including implicit flow handler, JWT support etc... Most of the code you need to write is the persistence of the tokens.

This makes it very easy to have an OAuth2 server and can be a good solution avoiding custom security mechanism handling which are often hard to maintain on the long term. The JWT integration also opens very nice doors for applications with a javascript frontend since the JWT can hold all the data you want and can avoid several round trips with the server for user’s metadata.

From the same author:

In the same category: