
com.wultra.security.powerauth.rest.client.PowerAuthFido2RestClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powerauth-rest-client-spring Show documentation
Show all versions of powerauth-rest-client-spring Show documentation
PowerAuth Server REST Service Client
The newest version!
/*
* PowerAuth Server and related software components
* Copyright (C) 2023 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
*/
package com.wultra.security.powerauth.rest.client;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wultra.core.rest.client.base.DefaultRestClient;
import com.wultra.core.rest.client.base.RestClient;
import com.wultra.core.rest.client.base.RestClientException;
import com.wultra.security.powerauth.fido2.client.PowerAuthFido2Client;
import com.wultra.security.powerauth.fido2.model.entity.AuthenticatorAssertionResponse;
import com.wultra.security.powerauth.fido2.model.entity.AuthenticatorParameters;
import com.wultra.security.powerauth.fido2.model.error.PowerAuthFido2Exception;
import com.wultra.security.powerauth.fido2.model.error.PowerAuthError;
import com.wultra.security.powerauth.fido2.model.request.*;
import com.wultra.security.powerauth.fido2.model.response.*;
import io.getlime.core.rest.model.base.request.ObjectRequest;
import io.getlime.core.rest.model.base.response.ObjectResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Class implementing a PowerAuth REST client.
*
* @author Roman Strobl, [email protected]
*
*/
public class PowerAuthFido2RestClient implements PowerAuthFido2Client {
private static final Logger logger = LoggerFactory.getLogger(PowerAuthFido2RestClient.class);
private static final String PA_REST_FIDO2_PREFIX = "/fido2";
private static final MultiValueMap EMPTY_MULTI_MAP = new LinkedMultiValueMap<>();
private final RestClient restClient;
private final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
/**
* PowerAuth REST client constructor.
*
* @param baseUrl BASE URL of REST endpoints.
*/
public PowerAuthFido2RestClient(String baseUrl) throws PowerAuthFido2Exception {
this(baseUrl, new PowerAuthFido2RestClientConfiguration());
}
/**
* PowerAuth REST client constructor.
*
* @param baseUrl Base URL of REST endpoints.
*/
public PowerAuthFido2RestClient(String baseUrl, PowerAuthFido2RestClientConfiguration config) throws PowerAuthFido2Exception {
final DefaultRestClient.Builder builder = DefaultRestClient.builder().baseUrl(baseUrl)
.acceptInvalidCertificate(config.isAcceptInvalidSslCertificate())
.connectionTimeout(config.getConnectTimeout())
.responseTimeout(config.getResponseTimeout())
.maxIdleTime(config.getMaxIdleTime())
.maxLifeTime(config.getMaxLifeTime())
.maxInMemorySize(config.getMaxMemorySize());
if (config.isProxyEnabled()) {
final DefaultRestClient.ProxyBuilder proxyBuilder = builder.proxy().host(config.getProxyHost()).port(config.getProxyPort());
if (config.getProxyUsername() != null) {
proxyBuilder.username(config.getProxyUsername()).password(config.getProxyPassword());
}
}
if (config.getPowerAuthClientToken() != null) {
builder.httpBasicAuth().username(config.getPowerAuthClientToken()).password(config.getPowerAuthClientSecret());
}
if (config.getDefaultHttpHeaders() != null) {
builder.defaultHttpHeaders(config.getDefaultHttpHeaders());
}
if (config.getFilter() != null) {
builder.filter(config.getFilter());
}
try {
restClient = builder.build();
} catch (RestClientException ex) {
throw new PowerAuthFido2Exception("REST client initialization failed, error: " + ex.getMessage(), ex);
}
}
/**
* Call the PowerAuth FIDO2 API.
*
* @param path Path of the endpoint.
* @param request Request object.
* @param queryParams HTTP query parameters.
* @param httpHeaders HTTP headers.
* @param responseType Response type.
* @return Response.
*/
private T callFido2RestApi(String path, Object request, MultiValueMap queryParams, MultiValueMap httpHeaders, Class responseType) throws PowerAuthFido2Exception {
final ObjectRequest> objectRequest = new ObjectRequest<>(request);
try {
final ObjectResponse objectResponse = restClient.postObject(PA_REST_FIDO2_PREFIX + path, objectRequest, queryParams, httpHeaders, responseType);
return objectResponse.getResponseObject();
} catch (RestClientException ex) {
if (ex.getStatusCode() == null) {
// Logging for network errors when port is closed
logger.warn("PowerAuth FIDO2 service is not accessible, error: {}", ex.getMessage());
logger.debug(ex.getMessage(), ex);
} else if (ex.getStatusCode() == HttpStatus.NOT_FOUND) {
// Logging for 404 errors
logger.warn("PowerAuth FIDO2 service is not available, error: {}", ex.getMessage());
logger.debug(ex.getMessage(), ex);
} else if (ex.getStatusCode() == HttpStatus.BAD_REQUEST) {
// Error handling for PowerAuth errors
handleBadRequestError(ex);
}
// Error handling for generic HTTP errors
throw new PowerAuthFido2Exception(ex.getMessage(), ex);
}
}
/**
* Handle the HTTP response with BAD_REQUEST status code.
* @param ex Exception which captured the error.
* @throws PowerAuthFido2Exception PowerAuth client exception.
*/
private void handleBadRequestError(RestClientException ex) throws PowerAuthFido2Exception {
// Try to parse exception into PowerAuthError model class
try {
final TypeReference> typeReference = new TypeReference<>(){};
final ObjectResponse error = objectMapper.readValue(ex.getResponse(), typeReference);
if (error == null || error.getResponseObject() == null) {
throw new PowerAuthFido2Exception("Invalid response object");
}
throw new PowerAuthFido2Exception(error.getResponseObject().getMessage(), ex, error.getResponseObject());
} catch (IOException ex2) {
// Parsing failed, return a regular error
throw new PowerAuthFido2Exception(ex.getMessage(), ex);
}
}
@Override
public RegisteredAuthenticatorsResponse getRegisteredAuthenticatorList(RegisteredAuthenticatorsRequest request) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations/list", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegisteredAuthenticatorsResponse.class);
}
@Override
public RegisteredAuthenticatorsResponse getRegisteredAuthenticatorList(RegisteredAuthenticatorsRequest request, MultiValueMap queryParams, MultiValueMap httpHeaders) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations/list", request, queryParams, httpHeaders, RegisteredAuthenticatorsResponse.class);
}
@Override
public RegisteredAuthenticatorsResponse getRegisteredAuthenticatorList(String userId, String applicationId) throws PowerAuthFido2Exception {
final RegisteredAuthenticatorsRequest request = new RegisteredAuthenticatorsRequest();
request.setUserId(userId);
request.setApplicationId(applicationId);
return callFido2RestApi("/registrations/list", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegisteredAuthenticatorsResponse.class);
}
@Override
public RegistrationChallengeResponse requestRegistrationChallenge(RegistrationChallengeRequest request) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations/challenge", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegistrationChallengeResponse.class);
}
@Override
public RegistrationChallengeResponse requestRegistrationChallenge(RegistrationChallengeRequest request, MultiValueMap queryParams, MultiValueMap httpHeaders) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations/challenge", request, queryParams, httpHeaders, RegistrationChallengeResponse.class);
}
@Override
public RegistrationChallengeResponse requestRegistrationChallenge(String userId, String applicationId) throws PowerAuthFido2Exception {
final RegistrationChallengeRequest request = new RegistrationChallengeRequest();
request.setUserId(userId);
request.setApplicationId(applicationId);
return callFido2RestApi("/registrations/challenge", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegistrationChallengeResponse.class);
}
@Override
public RegistrationResponse register(RegistrationRequest request) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegistrationResponse.class);
}
@Override
public RegistrationResponse register(RegistrationRequest request, MultiValueMap queryParams, MultiValueMap httpHeaders) throws PowerAuthFido2Exception {
return callFido2RestApi("/registrations", request, queryParams, httpHeaders, RegistrationResponse.class);
}
@Override
public RegistrationResponse register(String applicationId, String activationName, String expectedChallenge, AuthenticatorParameters authenticatorParameters) throws PowerAuthFido2Exception {
RegistrationRequest request = new RegistrationRequest();
request.setApplicationId(applicationId);
request.setActivationName(activationName);
request.setExpectedChallenge(expectedChallenge);
request.setAuthenticatorParameters(authenticatorParameters);
return callFido2RestApi("/registrations", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, RegistrationResponse.class);
}
@Override
public AssertionChallengeResponse requestAssertionChallenge(AssertionChallengeRequest request) throws PowerAuthFido2Exception {
return callFido2RestApi("/assertions/challenge", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, AssertionChallengeResponse.class);
}
@Override
public AssertionChallengeResponse requestAssertionChallenge(AssertionChallengeRequest request, MultiValueMap queryParams, MultiValueMap httpHeaders) throws PowerAuthFido2Exception {
return callFido2RestApi("/assertions/challenge", request, queryParams, httpHeaders, AssertionChallengeResponse.class);
}
@Override
public AssertionChallengeResponse requestAssertionChallenge(List applicationIds, String externalId, String operationType, Map parameters) throws PowerAuthFido2Exception {
final AssertionChallengeRequest request = new AssertionChallengeRequest();
return callFido2RestApi("/assertions/challenge", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, AssertionChallengeResponse.class);
}
@Override
public AssertionVerificationResponse authenticate(AssertionVerificationRequest request) throws PowerAuthFido2Exception {
return callFido2RestApi("/assertions", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, AssertionVerificationResponse.class);
}
@Override
public AssertionVerificationResponse authenticate(AssertionVerificationRequest request, MultiValueMap queryParams, MultiValueMap httpHeaders) throws PowerAuthFido2Exception {
return callFido2RestApi("/assertions", request, queryParams, httpHeaders, AssertionVerificationResponse.class);
}
@Override
public AssertionVerificationResponse authenticate(String id, String type, String authenticatorAttachment, AuthenticatorAssertionResponse response,
String applicationId, String relyingPartyId, List allowedOrigins, List allowedTopOrigins,
boolean requiresUserVerification, String expectedChallenge) throws PowerAuthFido2Exception {
final AssertionVerificationRequest request = new AssertionVerificationRequest();
request.setCredentialId(id);
request.setType(type);
request.setAuthenticatorAttachment(authenticatorAttachment);
request.setResponse(response);
request.setApplicationId(applicationId);
request.setRelyingPartyId(relyingPartyId);
request.setAllowedOrigins(allowedOrigins);
request.setAllowedTopOrigins(allowedTopOrigins);
request.setRequiresUserVerification(requiresUserVerification);
request.setExpectedChallenge(expectedChallenge);
return callFido2RestApi("/assertions", request, EMPTY_MULTI_MAP, EMPTY_MULTI_MAP, AssertionVerificationResponse.class);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy