/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.joda.time.DateTime; import org.opensaml.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.encryption.Encrypter; import org.opensaml.saml2.encryption.Encrypter.KeyPlacement; import org.opensaml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCriteria; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.xml.encryption.EncryptionException; import org.opensaml.xml.encryption.EncryptionParameters; import org.opensaml.xml.encryption.KeyEncryptionParameters; import org.opensaml.xml.security.CriteriaSet; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.criteria.EntityIDCriteria; import org.opensaml.xml.security.criteria.UsageCriteria; import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory; import org.opensaml.xml.security.x509.X509Credential; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.ArtifactBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.assertion.PVP2AssertionBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.InvalidAssertionConsumerServiceException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.InvalidAssertionEncryptionException; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; public class AuthnRequestHandler implements IRequestHandler, PVPConstants { public boolean handleObject(MOARequest obj) { return (obj.getSamlRequest() instanceof AuthnRequest); } public String process(MOARequest obj, HttpServletRequest req, HttpServletResponse resp, AuthenticationSession authSession) throws MOAIDException { if (!handleObject(obj)) { throw new MOAIDException("pvp2.13", null); } //get basic information AuthnRequest authnRequest = (AuthnRequest) obj.getSamlRequest(); EntityDescriptor peerEntity = obj.getEntityMetadata(); SPSSODescriptor spSSODescriptor = peerEntity .getSPSSODescriptor(SAMLConstants.SAML20P_NS); //get AssertionConsumingService Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); int idx = 0; if (aIdx != null) { idx = aIdx.intValue(); } else { idx = SAML2Utils.getDefaultAssertionConsumerServiceIndex(spSSODescriptor); } AssertionConsumerService consumerService = spSSODescriptor .getAssertionConsumerServices().get(idx); if (consumerService == null) { throw new InvalidAssertionConsumerServiceException(idx); } DateTime date = new DateTime(); //build Assertion Assertion assertion = PVP2AssertionBuilder.buildAssertion(authnRequest, authSession, peerEntity, date, consumerService); Response authResponse = SAML2Utils.createSAMLObject(Response.class); Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); //change to entity value from entity name to IDP EntityID (URL) nissuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); nissuer.setFormat(NameID.ENTITY); authResponse.setIssuer(nissuer); authResponse.setInResponseTo(authnRequest.getID()); //set responseID String remoteSessionID = SAML2Utils.getSecureIdentifier(); authResponse.setID(remoteSessionID); //SAML2 response required IssueInstant authResponse.setIssueInstant(date); authResponse.setStatus(SAML2Utils.getSuccessStatus()); String oaURL = consumerService.getLocation(); //check, if metadata includes an encryption key MetadataCredentialResolver mdCredResolver = new MetadataCredentialResolver(MOAMetadataProvider.getInstance()); CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add( new EntityIDCriteria(obj.getSamlRequest().getIssuer().getValue()) ); criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); criteriaSet.add( new UsageCriteria(UsageType.ENCRYPTION) ); X509Credential encryptionCredentials = null; try { encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); } catch (SecurityException e2) { Logger.warn("Can not extract the Assertion Encryption-Key from metadata", e2); throw new InvalidAssertionEncryptionException(); } if (encryptionCredentials != null) { //encrypt SAML2 assertion try { EncryptionParameters dataEncParams = new EncryptionParameters(); dataEncParams.setAlgorithm(PVPConstants.DEFAULT_SYM_ENCRYPTION_METHODE); List keyEncParamList = new ArrayList(); KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); keyEncParam.setEncryptionCredential(encryptionCredentials); keyEncParam.setAlgorithm(PVPConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); KeyInfoGeneratorFactory kigf = Configuration.getGlobalSecurityConfiguration() .getKeyInfoGeneratorManager().getDefaultManager() .getFactory(encryptionCredentials); keyEncParam.setKeyInfoGenerator(kigf.newInstance()); keyEncParamList.add(keyEncParam); Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); //samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); samlEncrypter.setKeyPlacement(KeyPlacement.PEER); EncryptedAssertion encryptAssertion = null; encryptAssertion = samlEncrypter.encrypt(assertion); authResponse.getEncryptedAssertions().add(encryptAssertion); } catch (EncryptionException e1) { Logger.warn("Can not encrypt the PVP2 assertion", e1); throw new InvalidAssertionEncryptionException(); } } else { authResponse.getAssertions().add(assertion); } IEncoder binding = null; if (consumerService.getBinding().equals( SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { binding = new RedirectBinding(); } else if (consumerService.getBinding().equals( SAMLConstants.SAML2_ARTIFACT_BINDING_URI)) { // TODO: not supported YET!! binding = new ArtifactBinding(); } else if (consumerService.getBinding().equals( SAMLConstants.SAML2_POST_BINDING_URI)) { binding = new PostBinding(); } if (binding == null) { throw new BindingNotSupportedException(consumerService.getBinding()); } try { binding.encodeRespone(req, resp, authResponse, oaURL); // TODO add remoteSessionID to AuthSession ExternalPVPSessionStore // Logger logger = new Logger(); // logger.debug("Redirect Binding Request = " + PrettyPrinter.prettyPrint(SAML2Utils.asDOMDocument(authResponse))); return assertion.getID(); } catch (MessageEncodingException e) { Logger.error("Message Encoding exception", e); throw new MOAIDException("pvp2.01", null, e); } catch (SecurityException e) { Logger.error("Security exception", e); throw new MOAIDException("pvp2.01", null, e); // } catch (TransformerException e) { // Logger.error("Security exception", e); // throw new MOAIDException("pvp2.01", null, e); // } catch (IOException e) { // Logger.error("Security exception", e); // throw new MOAIDException("pvp2.01", null, e); // } catch (MarshallingException e) { // Logger.error("Security exception", e); // throw new MOAIDException("pvp2.01", null, e); } } }