
io.getlime.rest.api.security.provider.PowerAuthAuthenticationProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powerauth-restful-security Show documentation
Show all versions of powerauth-restful-security Show documentation
PowerAuth 2.0 RESTful API Security Additions
The newest version!
/**
* Copyright 2015 Lime - HighTech Solutions s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.getlime.rest.api.security.provider;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import com.google.common.io.BaseEncoding;
import javax.servlet.http.HttpServletRequest;
import io.getlime.powerauth.soap.VerifySignatureRequest;
import io.getlime.powerauth.soap.VerifySignatureResponse;
import io.getlime.rest.api.security.application.PowerAuthApplicationConfiguration;
import io.getlime.rest.api.security.authentication.PowerAuthApiAuthentication;
import io.getlime.rest.api.security.authentication.PowerAuthAuthentication;
import io.getlime.rest.api.security.exception.PowerAuthAuthenticationException;
import io.getlime.rest.api.security.filter.PowerAuthRequestFilter;
import io.getlime.security.powerauth.lib.enums.PowerAuthSignatureTypes;
import io.getlime.security.powerauth.lib.util.http.PowerAuthHttpBody;
import io.getlime.security.powerauth.lib.util.http.PowerAuthHttpHeader;
import io.getlime.security.soap.client.PowerAuthServiceClient;
/**
* Implementation of PowerAuth authentication provider.
*
* @author Petr Dvorak
*
*/
@Component
public class PowerAuthAuthenticationProvider implements AuthenticationProvider {
@Autowired
private PowerAuthServiceClient powerAuthClient;
@Autowired(required=false)
private PowerAuthApplicationConfiguration applicationConfiguration;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
PowerAuthAuthentication powerAuthAuthentication = (PowerAuthAuthentication) authentication;
VerifySignatureRequest soapRequest = new VerifySignatureRequest();
soapRequest.setActivationId(powerAuthAuthentication.getActivationId());
soapRequest.setApplicationKey(powerAuthAuthentication.getApplicationKey());
soapRequest.setSignature(powerAuthAuthentication.getSignature());
soapRequest.setSignatureType(powerAuthAuthentication.getSignatureType());
try {
String payload = PowerAuthHttpBody.getSignatureBaseString(
powerAuthAuthentication.getHttpMethod(),
powerAuthAuthentication.getRequestUri(),
powerAuthAuthentication.getNonce(),
powerAuthAuthentication.getData()
);
soapRequest.setData(payload);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(PowerAuthAuthenticationProvider.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
VerifySignatureResponse soapResponse = powerAuthClient.verifySignature(soapRequest);
if (soapResponse.isSignatureValid()) {
PowerAuthApiAuthentication apiAuthentication = new PowerAuthApiAuthentication();
apiAuthentication.setActivationId(soapResponse.getActivationId());
apiAuthentication.setUserId(soapResponse.getUserId());
apiAuthentication.setAuthenticated(true);
return apiAuthentication;
} else {
return null;
}
}
@Override
public boolean supports(Class> authentication) {
if (authentication == PowerAuthAuthentication.class) {
return true;
}
return false;
}
/**
* Validate the signature from the PowerAuth 2.0 HTTP header against the provided HTTP method, request body and URI identifier.
* Make sure to accept only allowed signatures.
* @param httpMethod HTTP method (GET, POST, ...)
* @param httpBody Body of the HTTP request.
* @param requestUriIdentifier Request URI identifier.
* @param httpAuthorizationHeader PowerAuth 2.0 HTTP authorization header.
* @param allowedSignatureTypes Allowed types of the signature.
* @return Instance of a PowerAuthApiAuthentication on successful authorization.
* @throws Exception In case authorization fails, exception is raised.
*/
public PowerAuthApiAuthentication validateRequestSignature(String httpMethod, byte[] httpBody, String requestUriIdentifier, String httpAuthorizationHeader, List allowedSignatureTypes) throws Exception {
// Check for HTTP PowerAuth signature header
if (httpAuthorizationHeader == null || httpAuthorizationHeader.equals("undefined")) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_INVALID_EMPTY");
}
// Parse HTTP header
Map httpHeaderInfo = PowerAuthHttpHeader.parsePowerAuthSignatureHTTPHeader(httpAuthorizationHeader);
// Check if the parsing was successful
if (httpHeaderInfo == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_INVALID_EMPTY");
}
// Fetch HTTP header attributes
String activationId = httpHeaderInfo.get(PowerAuthHttpHeader.ACTIVATION_ID);
if (activationId == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_ACTIVATION_ID_EMPTY");
}
String nonce = httpHeaderInfo.get(PowerAuthHttpHeader.NONCE);
if (nonce == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_NONCE_EMPTY");
}
String signatureType = httpHeaderInfo.get(PowerAuthHttpHeader.SIGNATURE_TYPE);
if (signatureType == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_TYPE_EMPTY");
}
String signature = httpHeaderInfo.get(PowerAuthHttpHeader.SIGNATURE);
if (signature == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_EMPTY");
}
String applicationId = httpHeaderInfo.get(PowerAuthHttpHeader.APPLICATION_ID);
if (applicationId == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_APPLICATION_EMPTY");
}
// Check if the application is allowed, "true" is the default behavior
if (applicationConfiguration != null) {
boolean isApplicationAllowed = applicationConfiguration.isAllowedApplicationKey(applicationId);
if (!isApplicationAllowed) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_INVALID_APPLICATION_ID");
}
}
// Check if the signature type is allowed
PowerAuthSignatureTypes expectedSignatureType = PowerAuthSignatureTypes.getEnumFromString(signatureType);
if (!allowedSignatureTypes.contains(expectedSignatureType)) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_TYPE_INVALID");
}
// Configure PowerAuth authentication object
PowerAuthAuthentication powerAuthAuthentication = new PowerAuthAuthentication();
powerAuthAuthentication.setActivationId(activationId);
powerAuthAuthentication.setApplicationKey(applicationId);
powerAuthAuthentication.setNonce(BaseEncoding.base64().decode(nonce));
powerAuthAuthentication.setSignatureType(signatureType);
powerAuthAuthentication.setSignature(signature);
powerAuthAuthentication.setHttpMethod(httpMethod);
powerAuthAuthentication.setRequestUri(requestUriIdentifier);
powerAuthAuthentication.setData(httpBody);
// Call the authentication
PowerAuthApiAuthentication auth = (PowerAuthApiAuthentication) this.authenticate(powerAuthAuthentication);
// In case authentication is null, throw PowerAuth exception
if (auth == null) {
throw new PowerAuthAuthenticationException("POWER_AUTH_SIGNATURE_INVALID_VALUE");
}
return auth;
}
/**
* The same as {{@link #validateRequestSignature(String, byte[], String, String, List)} but uses default accepted signature type (2FA or 3FA).
* @param httpMethod HTTP method (GET, POST, ...)
* @param httpBody Request body
* @param requestUriIdentifier Request URI identifier.
* @param httpAuthorizationHeader PowerAuth 2.0 HTTP authorization header.
* @return Instance of a PowerAuthApiAuthentication on successful authorization.
* @throws Exception In case authorization fails, exception is raised.
*/
public PowerAuthApiAuthentication validateRequestSignature(String httpMethod, byte[] httpBody, String requestUriIdentifier, String httpAuthorizationHeader) throws Exception {
List defaultAllowedSignatureTypes = new ArrayList<>();
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE);
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_BIOMETRY);
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE_BIOMETRY);
return this.validateRequestSignature(httpMethod, httpBody, requestUriIdentifier, httpAuthorizationHeader, defaultAllowedSignatureTypes);
}
/**
* Validate a request signature, make sure only supported signature types are used.
* @param servletRequest HTTPServletRequest with signed data.
* @param requestUriIdentifier Request URI identifier.
* @param httpAuthorizationHeader PowerAuth 2.0 HTTP authorization header.
* @param allowedSignatureTypes Allowed types of signatures.
* @return Instance of a PowerAuthApiAuthentication on successful authorization.
* @throws Exception In case authorization fails, exception is raised.
*/
public PowerAuthApiAuthentication validateRequestSignature(HttpServletRequest servletRequest, String requestUriIdentifier, String httpAuthorizationHeader, List allowedSignatureTypes) throws Exception {
// Get HTTP method and body bytes
String requestMethod = servletRequest.getMethod().toUpperCase();
String requestBodyString = ((String) servletRequest.getAttribute(PowerAuthRequestFilter.POWERAUTH_SIGNATURE_BASE_STRING));
byte[] requestBodyBytes = requestBodyString == null ? null : BaseEncoding.base64().decode(requestBodyString);
return this.validateRequestSignature(requestMethod, requestBodyBytes, requestUriIdentifier, httpAuthorizationHeader, allowedSignatureTypes);
}
/**
* The same as {{@link #validateRequestSignature(HttpServletRequest, String, String, List)} but uses default accepted signature type (2FA or 3FA).
* @param servletRequest HTTPServletRequest with signed data.
* @param requestUriIdentifier Request URI identifier.
* @param httpAuthorizationHeader PowerAuth 2.0 HTTP authorization header.
* @return Instance of a PowerAuthApiAuthentication on successful authorization.
* @throws Exception In case authorization fails, exception is raised.
*/
public PowerAuthApiAuthentication validateRequestSignature(HttpServletRequest servletRequest, String requestUriIdentifier, String httpAuthorizationHeader) throws Exception {
List defaultAllowedSignatureTypes = new ArrayList<>();
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE);
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_BIOMETRY);
defaultAllowedSignatureTypes.add(PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE_BIOMETRY);
return this.validateRequestSignature(servletRequest, requestUriIdentifier, httpAuthorizationHeader, defaultAllowedSignatureTypes);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy