<commit_before>/**
 * 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 <NAME>
 *
 */
@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<PowerAuthSignatureTypes> 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<String, String> httpHeaderInfo = PowerAuthHttpHeader.parsePowerAuthSignatureHTTPHeader(httpAuthorizationHeader);
		
		// 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) {<commit_msg>Add null check for the HTTP header parsing<commit_after>/**
 * 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 <NAME>
 *
 */
@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<PowerAuthSignatureTypes> 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<String, String> 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) {
{'fraction_non_alphanumeric': 0.08227900438270074, 'fraction_numerical': 0.0019846192011907715, 'mean_word_length': 6.011014492753623, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4675763', 'n_tokens_mistral': 3282, 'n_tokens_neox': 3093, 'n_words': 753}