package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder;
import com.google.common.base.Strings;
import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.codec.Base64Support;
/**
* SAML2 Post-Binding decoder with same EAAF specific hardening regarding http
* request-parameter processing.
*
* @author tlenz
*
*/
@Slf4j
public class EaafHttpPostDecoder extends HTTPPostDecoder {
@Override
protected InputStream getBase64DecodedMessage(final HttpServletRequest request)
throws MessageDecodingException {
log.debug("Getting Base64 encoded message from request");
String encodedMessage = getLastParameterFromRequest(request, "SAMLRequest");
if (Strings.isNullOrEmpty(encodedMessage)) {
encodedMessage = getLastParameterFromRequest(request, "SAMLResponse");
}
if (Strings.isNullOrEmpty(encodedMessage)) {
log.info("Request did not contain either a SAMLRequest or "
+ "SAMLResponse paramter. Invalid request for SAML 2 HTTP POST binding.");
throw new MessageDecodingException("No SAML message present in request");
}
log.trace("Base64 decoding SAML message:\n{}", encodedMessage);
final byte[] decodedBytes = Base64Support.decode(encodedMessage);
if (decodedBytes == null) {
log.info("Unable to Base64 decode SAML message");
throw new MessageDecodingException("Unable to Base64 decode SAML message");
}
log.trace("Decoded SAML message:\n{}", new String(decodedBytes));
return new ByteArrayInputStream(decodedBytes);
}
/**
* EAAF specific unmarshaller perform XML schema validation before unmarshalling
* the SAML message.
*
*/
@Override
protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException {
return Saml2Utils.unmarshallMessage(messageStream);
}
/**
* Always read the last parameter with this name from request to get a strict
* deterministic behavior.
*
* If more than one parameters with the same name exists, this method
* always select the last parameter value.
*
* @param request Incoming http request
* @param paramName Name of the http parameter
* @return the last parameter value with this name, or null
if the
* parameter not exists
*/
@Nullable
private String getLastParameterFromRequest(@Nonnull HttpServletRequest request, @Nonnull String paramName) {
final String[] values = request.getParameterValues(paramName);
if (values != null && values.length > 0) {
return values[values.length - 1];
}
return null;
}
}