All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.clouway.oauth2.client.JwtTokenSource Maven / Gradle / Ivy

The newest version!
package com.clouway.oauth2.client;

import com.clouway.oauth2.client.Pem.Block;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * JwtTokenSource is an implementation of {@link TokenSource} which uses JWT request to obtain JWT token from the Identity Provider.
 *
 *
 * @author Miroslav Genov ([email protected])
 */
class JwtTokenSource implements TokenSource {
  private final JwtConfig config;

  // TODO(mgenov): connect and read timeouts could be moved as params
  private final OkHttpClient client = new Builder()
              .connectTimeout(3000, TimeUnit.SECONDS)
              .readTimeout(3000, TimeUnit.SECONDS)
              .build();

  JwtTokenSource(JwtConfig config) {
    this.config = config;
  }

  @Override
  public Optional token(Date instant) throws IOException {
    PrivateKey privateKey = readPrivateKey();

    String jwtToken = Jwts.builder()
            .setIssuer(config.email)
            .setSubject(config.subject)
            .setAudience(config.tokenUrl)
            .signWith(SignatureAlgorithm.RS256, privateKey)
            .compact();

    Request request = new Request.Builder()
            .url(config.tokenUrl)
            .post(new FormBody.Builder()
                    .add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
                    .add("assertion", jwtToken)
                    .build()
            )
            .build();

    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) {
      throw new IOException("Got unexpected response from the Identity Provider: " + response);
    }

    try {
      JSONObject json = new JSONObject(response.body().string());

      String accessToken = json.getString("access_token");

      Long expiresInSeconds = json.getLong("expires_in");
      Long expiresInMilliseconds = expiresInSeconds * 1000;

      // Expiry from instant till the token duration
      Date expiry = new Date(instant.getTime() + expiresInMilliseconds);

      return Optional.of(new Token(accessToken, expiry));
    } catch (JSONException e) {
      throw new IOException("Not well formed response was returned from the backend.", e);
    }
  }

  private PrivateKey readPrivateKey() throws IOException {
    try {
      Block block = new Pem().parse(new ByteArrayInputStream(config.privateKey));
      KeyFactory kf = KeyFactory.getInstance("RSA");
      return kf.generatePrivate(new PKCS8EncodedKeySpec(block.getBytes()));
    } catch (NoSuchAlgorithmException e) {
      throw new IllegalStateException("The RSA algorithm is not supported.");
    } catch (InvalidKeySpecException e) {
      throw new IllegalArgumentException("The provided key was not valid or not well formated.", e);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy