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

io.camunda.identity.sdk.impl.generic.GenericAuthentication Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. Licensed under a proprietary license. See the
 * License.txt file for more information. You may not use this file except in compliance with the
 * proprietary license.
 */
package io.camunda.identity.sdk.impl.generic;

import static io.camunda.identity.sdk.utility.UrlUtility.combinePaths;

import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.JwkProviderBuilder;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.camunda.identity.sdk.IdentityConfiguration;
import io.camunda.identity.sdk.authentication.AbstractAuthentication;
import io.camunda.identity.sdk.authentication.AuthorizeUriBuilder;
import io.camunda.identity.sdk.authentication.Tokens;
import io.camunda.identity.sdk.authentication.dto.AuthCodeDto;
import io.camunda.identity.sdk.authentication.exception.CodeExchangeException;
import io.camunda.identity.sdk.impl.dto.AccessTokenDto;
import io.camunda.identity.sdk.impl.dto.WellKnownConfiguration;
import io.camunda.identity.sdk.impl.rest.RestClient;
import io.camunda.identity.sdk.impl.rest.request.ClientTokenRequest;
import io.camunda.identity.sdk.impl.rest.request.ExchangeAuthCodeRequest;
import io.camunda.identity.sdk.impl.rest.request.PermissionsRequest;
import io.camunda.identity.sdk.impl.rest.request.RenewTokenRequest;
import io.camunda.identity.sdk.impl.rest.request.RevokeTokenRequest;
import io.camunda.identity.sdk.impl.rest.request.WellKnownRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

public class GenericAuthentication extends AbstractAuthentication {
  static final String PERMISSIONS_PATH = "/api/permissions";
  static final String FOR_TOKEN_PATH = "/for-token";

  protected JwkProvider jwkProvider;
  private WellKnownConfiguration wellKnownConfiguration;

  public GenericAuthentication(
      final IdentityConfiguration configuration,
      final RestClient restClient
  ) {
    super(configuration, restClient);
  }

  @Override
  public AuthorizeUriBuilder authorizeUriBuilder(final String redirectUri) {
    return new GenericAuthorizeUriBuilder(
        configuration,
        wellKnownConfiguration().getAuthorizationEndpoint(),
        redirectUri
    );
  }

  @Override
  public Tokens exchangeAuthCode(
      final AuthCodeDto authCodeDto,
      final String redirectUri
  ) throws CodeExchangeException {
    Validate.notNull(authCodeDto, "authCodeDto must not be null");
    Validate.notNull(redirectUri, "redirectUri must not be null");

    if (authCodeDto.getError() != null && !authCodeDto.getError().isBlank()) {
      throw new CodeExchangeException(authCodeDto.getError());
    }

    Validate.notEmpty(authCodeDto.getCode(), "code must not be null");

    final ExchangeAuthCodeRequest request = new ExchangeAuthCodeRequest(
        configuration,
        wellKnownConfiguration().getTokenEndpoint(),
        redirectUri,
        authCodeDto.getCode()
    );
    final AccessTokenDto accessTokenDto = restClient.request(request);

    return this.fromAccessTokenDto(accessTokenDto);
  }

  @Override
  protected Tokens requestFreshToken(final String audience) {
    final ClientTokenRequest request = new ClientTokenRequest(
        configuration,
        wellKnownConfiguration().getTokenEndpoint(),
        audience,
        null
    );
    final AccessTokenDto accessTokenDto = restClient.request(request);

    return fromAccessTokenDto(accessTokenDto);
  }

  @Override
  public Tokens renewToken(final String refreshToken) {
    Validate.notEmpty(refreshToken, "refreshToken can not be empty");

    final RenewTokenRequest request = new RenewTokenRequest(
        configuration,
        wellKnownConfiguration().getTokenEndpoint(),
        refreshToken
    );
    final AccessTokenDto accessTokenDto = restClient.request(request);

    return this.fromAccessTokenDto(accessTokenDto);
  }

  @Override
  public void revokeToken(final String refreshToken) {
    Validate.notEmpty(refreshToken, "refreshToken can not be empty");

    if (!isRevokeAvailable()) {
      throw new UnsupportedOperationException("revocation endpoint is not configured");
    }

    final RevokeTokenRequest request = new RevokeTokenRequest(
        configuration,
        wellKnownConfiguration().getRevocationEndpoint(),
        refreshToken
    );
    restClient.request(request);
  }

  @Override
  public List getPermissions(final DecodedJWT token, final String audience) {
    if (StringUtils.isNotBlank(audience)) {
      final PermissionsRequest request = new PermissionsRequest(
          combinePaths(configuration.getBaseUrl(), PERMISSIONS_PATH + FOR_TOKEN_PATH),
          token.getToken(),
          audience
      );
      return restClient.request(request);
    }
    return Collections.emptyList();
  }

  @Override
  public boolean isM2MToken(final String token) {
    throw new NotImplementedException();
  }

  @Override
  public String getClientId(final String token) {
    throw new NotImplementedException();
  }

  @Override
  public Map> getAssignedOrganizations(final DecodedJWT token) {
    return Collections.emptyMap();
  }

  @Override
  protected JwkProvider jwkProvider() {
    final var jwksUrl = StringUtils.isNotEmpty(configuration.getJwksUrl())
        ? configuration.getJwksUrl()
        : wellKnownConfiguration().getJwksUri();

    if (jwkProvider == null) {
      try {
        jwkProvider = new JwkProviderBuilder(new URL(jwksUrl))
            .cached(JWKS_CACHE_SIZE, JWKS_CACHE_LIFETIME_DAYS, TimeUnit.DAYS)
            .build();
      } catch (final MalformedURLException e) {
        throw new IllegalStateException("invalid issuer url", e);
      }
    }
    return jwkProvider;
  }

  @Override
  protected WellKnownConfiguration wellKnownConfiguration() {
    if (wellKnownConfiguration == null) {
      final WellKnownRequest wellKnownRequest = new WellKnownRequest(configuration);
      wellKnownConfiguration = restClient.request(wellKnownRequest);
    }

    return wellKnownConfiguration;
  }

  protected Tokens fromAccessTokenDto(final AccessTokenDto dto) {
    return new Tokens(dto.getAccessToken(), dto.getRefreshToken(),
        dto.getExpiresIn(),
        dto.getScope(), dto.getTokenType());
  }

  @Override
  protected boolean isRevokeAvailable() {
    return wellKnownConfiguration().getRevocationEndpoint() != null;
  }

  @Override
  protected boolean isSingleSignOutAvailable() {
    return wellKnownConfiguration().getEndSessionEndpoint() != null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy