io.camunda.identity.sdk.impl.generic.GenericAuthentication Maven / Gradle / Ivy
/*
* 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 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.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.Validate;
public class GenericAuthentication extends AbstractAuthentication {
protected final RestClient restClient;
protected JwkProvider jwkProvider;
private WellKnownConfiguration wellKnownConfiguration;
public GenericAuthentication(
final IdentityConfiguration configuration,
final RestClient restClient
) {
super(configuration);
this.restClient = 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 (wellKnownConfiguration().getRevocationEndpoint() == null) {
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) {
return List.of("read:*", "write:*");
}
@Override
protected List getGroups(final DecodedJWT token) {
return Collections.emptyList();
}
@Override
public boolean isM2MToken(final String token) {
throw new NotImplementedException();
}
@Override
public String getClientId(final String token) {
throw new NotImplementedException();
}
@Override
protected Map> getAssignedOrganizations(final DecodedJWT token) {
return Collections.emptyMap();
}
@Override
protected JwkProvider jwkProvider() {
if (jwkProvider == null) {
try {
jwkProvider = new JwkProviderBuilder(new URL(wellKnownConfiguration().getJwksUri()))
.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;
}
private Tokens fromAccessTokenDto(final AccessTokenDto dto) {
return new Tokens(dto.getAccessToken(), dto.getRefreshToken(), dto.getExpiresIn(),
dto.getScope(), dto.getTokenType());
}
}