From 5c2b9a3f45eaa58193e0bb53322ac782b21a04e3 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 3 Jun 2014 17:08:53 +0200 Subject: update SLO --- .../at/gv/egovernment/moa/id/demoOA/Constants.java | 6 + .../moa/id/demoOA/servlet/pvp2/BuildMetadata.java | 10 +- .../id/demoOA/servlet/pvp2/DemoApplication.java | 12 +- .../moa/id/demoOA/servlet/pvp2/Index.java | 335 +++++++++++++++++++++ .../moa/id/demoOA/servlet/pvp2/SingleLogOut.java | 239 +++++++++++++++ .../moa/id/demoOA/utils/ApplicationBean.java | 13 + id/oa/src/main/webapp/WEB-INF/web.xml | 24 +- 7 files changed, 633 insertions(+), 6 deletions(-) create mode 100644 id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java create mode 100644 id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java index af1dd84be..d6d2b32da 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java @@ -28,4 +28,10 @@ public class Constants { public static final String SERVLET_PVP2ASSERTION = "demoapplication"; public static final String SESSION_PVP2REQUESTID = "pvp2requestid"; + + public static final String SERVLET_PVPSINGLELOGOUT = "singlelogout"; + + public static final String SESSION_NAMEID = "pvp2nameID"; + + public static final String SESSION_NAMEIDFORMAT = "pvp2nameIDFormat"; } diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java index 4c9bc6d76..24ba26a59 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java @@ -56,6 +56,7 @@ import org.opensaml.saml2.metadata.LocalizedString; import org.opensaml.saml2.metadata.NameIDFormat; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.ServiceName; +import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.impl.EncryptionMethodBuilder; import org.opensaml.xml.encryption.EncryptionConstants; import org.opensaml.xml.encryption.OAEPparams; @@ -238,10 +239,15 @@ public class BuildMetadata extends HttpServlet { postassertionConsumerService.setIndex(0); postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION); - + postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION); spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); + //set Single Log-Out service + SingleLogoutService sloService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + sloService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + sloService.setLocation(serviceURL + Constants.SERVLET_PVPSINGLELOGOUT); + spSSODescriptor.getSingleLogoutServices().add(sloService); + spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor); diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java index dcd478864..cde9451a4 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java @@ -73,6 +73,7 @@ import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; import at.gv.egovernment.moa.id.demoOA.Configuration; +import at.gv.egovernment.moa.id.demoOA.Constants; import at.gv.egovernment.moa.id.demoOA.PVPConstants; import at.gv.egovernment.moa.id.demoOA.utils.ApplicationBean; import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils; @@ -223,14 +224,19 @@ public class DemoApplication extends HttpServlet { birthday = attributes.get(x).getAttributeValues().get(0).getDOM().getTextContent(); } } - } + } + request.getSession().setAttribute(Constants.SESSION_NAMEIDFORMAT, + saml2assertion.getSubject().getNameID().getFormat()); + request.getSession().setAttribute(Constants.SESSION_NAMEID, + saml2assertion.getSubject().getNameID().getValue()); + } - + bean.setDateOfBirth(birthday); bean.setFamilyName(familyName); bean.setGivenName(givenName); bean.setLogin(true); - + setAnser(request, response, bean); return; diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java new file mode 100644 index 000000000..c68ea9b1f --- /dev/null +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * 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.demoOA.servlet.pvp2; + +import java.io.IOException; +import java.security.KeyStore; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.joda.time.DateTime; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; +import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.LogoutResponse; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; +import org.opensaml.security.MetadataCredentialResolver; +import org.opensaml.security.MetadataCredentialResolverFactory; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.ws.transport.http.HttpServletRequestAdapter; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.security.CriteriaSet; +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.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; +import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.id.demoOA.Configuration; +import at.gv.egovernment.moa.id.demoOA.exception.ConfigurationException; +import at.gv.egovernment.moa.id.demoOA.utils.ApplicationBean; +import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils; +import at.gv.egovernment.moa.util.DOMUtils; +import at.iaik.commons.util.MiscUtil; + + +public class Index extends HttpServlet { + + private static final long serialVersionUID = -2129228304760706063L; + private static final Logger log = LoggerFactory + .getLogger(Index.class); + + + private void process(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + + ApplicationBean bean = new ApplicationBean(); + + + String method = request.getMethod(); + HttpSession session = request.getSession(); + if (session == null) { + log.info("NO HTTP Session"); + bean.setErrorMessage("NO HTTP session"); + setAnser(request, response, bean); + return; + } + + if (method.equals("POST")) { + try { + Configuration config = Configuration.getInstance(); + + //Decode with HttpPost Binding + HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); + BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); + messageContext + .setInboundMessageTransport(new HttpServletRequestAdapter( + request)); + decode.decode(messageContext); + + SignableXMLObject samlResponse = (SignableXMLObject) messageContext.getInboundMessage(); + + Signature sign = samlResponse.getSignature(); + if (sign == null) { + log.info("Only http POST Requests can be used"); + bean.setErrorMessage("Only http POST Requests can be used"); + setAnser(request, response, bean); + return; + } + + //Validate Signature + SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + profileValidator.validate(sign); + + //Verify Signature + List keyInfoProvider = new ArrayList(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + + KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); + MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(config.getMetaDataProvier()); + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName())); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); + trustEngine.validate(sign, criteriaSet); + + log.info("PVP2 statusrequest or statusresponse is valid"); + + + if (samlResponse instanceof LogoutResponse) { + + LogoutResponse sloResp = (LogoutResponse) samlResponse; + + //set assertion + org.w3c.dom.Document doc = SAML2Utils.asDOMDocument(samlResponse); + String assertion = DOMUtils.serializeNode(doc); + bean.setAssertion(assertion); + + if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + + bean.setSuccessMessage("Der Single Log-Out Vorgang konnte erfolgreich durchgeführt werden."); + + setAnser(request, response, bean); + return; + + } else { + bean.setErrorMessage("Der Single Log-Out Vorgang war nicht erfolgreich.
Bitte schließen Sie aus sicherheitsgründen den Browser!"); + setAnser(request, response, bean); + return; + + } + + } else if (samlResponse instanceof LogoutRequest) { + //invalidate user session + request.getSession().invalidate(); + + //build LogOutResponse + LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + sloResp.setID(gen.generateIdentifier()); + sloResp.setIssueInstant(new DateTime()); + NameID name = SAML2Utils.createSAMLObject(NameID.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + name.setValue(serviceURL); + issuer.setValue(serviceURL); + issuer.setFormat(NameIDType.ENTITY); + sloResp.setIssuer(issuer); + + Status status = SAML2Utils.createSAMLObject(Status.class); + sloResp.setStatus(status); + StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); + statusCode.setValue(StatusCode.SUCCESS_URI); + status.setStatusCode(statusCode ); + + String entityname = config.getPVP2IDPMetadataEntityName(); + if (MiscUtil.isEmpty(entityname)) { + log.info("No IDP EntityName configurated"); + throw new ConfigurationException("No IDP EntityName configurated"); + } + + //get IDP metadata from metadataprovider + HTTPMetadataProvider idpmetadata = config.getMetaDataProvier(); + EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname); + if (idpEntity == null) { + log.info("IDP EntityName is not found in IDP Metadata"); + throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); + } + + //select authentication-service url from metadata + SingleLogoutService redirectEndpoint = null; + for (SingleLogoutService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) { + + //Get the service address for the binding you wish to use + if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + redirectEndpoint = sss; + } + } + sloResp.setDestination(redirectEndpoint.getLocation()); + + //sign authentication request + KeyStore keyStore = config.getPVP2KeyStore(); + X509Credential authcredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreAuthRequestKeyAlias(), + config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(authcredential); + sloResp.setSignature(signer); + + //generate Http-POST Binding message + VelocityEngine engine = new VelocityEngine(); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + engine.setProperty("classpath.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, + "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); + engine.init(); + + HTTPPostEncoder encoder = new HTTPPostEncoder(engine, + "templates/pvp_postbinding_template.html"); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + response, true); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); + service.setLocation(redirectEndpoint.getLocation());; + + context.setOutboundSAMLMessageSigningCredential(authcredential); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloResp); + context.setOutboundMessageTransport(responseAdapter); + context.setRelayState(messageContext.getRelayState()); + + encoder.encode(context); + + } else { + bean.setErrorMessage("Kein gültiger LogOut Request oder LogOut Response"); + setAnser(request, response, bean); + return; + + } + + + } catch (Exception e) { + log.warn("Internal error", e); + bean.setErrorMessage("Internal Error: " + e.getMessage()); + setAnser(request, response, bean); + return; + } + + } else { + bean.setErrorMessage("Die Demoapplikation unterstützt nur SAML2 POST-Binding."); + setAnser(request, response, bean); + return; + + } + } + + private void setAnser(HttpServletRequest request, HttpServletResponse response, ApplicationBean answersBean) throws ServletException, IOException { + // store bean in session + request.setAttribute("answers", answersBean); + + // you now can forward to some view, for example some results.jsp + request.getRequestDispatcher("demoapp.jsp").forward(request, response); + + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + process(request, response); + } + + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } +} diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java new file mode 100644 index 000000000..11cc020ff --- /dev/null +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * 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.demoOA.servlet.pvp2; + +import java.io.IOException; +import java.security.KeyStore; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.joda.time.DateTime; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDPolicy; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.core.Subject; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import at.gv.egovernment.moa.id.demoOA.Configuration; +import at.gv.egovernment.moa.id.demoOA.Constants; +import at.gv.egovernment.moa.id.demoOA.exception.ConfigurationException; +import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils; +import at.iaik.commons.util.MiscUtil; + + +/** + * Servlet implementation class Authenticate + */ +public class SingleLogOut extends HttpServlet { + private static final long serialVersionUID = 1L; + + private static final Logger log = LoggerFactory + .getLogger(SingleLogOut.class); + + /** + * @see HttpServlet#HttpServlet() + */ + public SingleLogOut() { + super(); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + builder = factory.newDocumentBuilder(); + + } catch (ParserConfigurationException e) { + log.warn("PVP2 AuthenticationServlet can not be initialized.", e); + } + } + + DocumentBuilder builder; + + + //generate AuthenticationRequest + protected void process(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + try { + + Configuration config = Configuration.getInstance(); + config.initializePVP2Login(); + + String nameIDFormat = (String) request.getSession().getAttribute(Constants.SESSION_NAMEIDFORMAT); + String nameID = (String) request.getSession().getAttribute(Constants.SESSION_NAMEID); + + if (MiscUtil.isEmpty(nameID) || MiscUtil.isEmpty(nameIDFormat)) { + log.warn("No user information found. Single Log-Out not possible"); + throw new ServletException("No user information found. Single Log-Out not possible"); + + } else + log.info("Fount user information for user nameID: " + nameID + + " , nameIDFormat: " + nameIDFormat + + ". Build Single Log-Out request ..."); + + //invalidate local session + request.getSession().invalidate(); + + //build Single LogOut request + LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + sloReq.setID(gen.generateIdentifier()); + sloReq.setIssueInstant(new DateTime()); + NameID name = SAML2Utils.createSAMLObject(NameID.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + name.setValue(serviceURL); + issuer.setValue(serviceURL); + issuer.setFormat(NameIDType.ENTITY); + sloReq.setIssuer(issuer); + + NameID userNameID = SAML2Utils.createSAMLObject(NameID.class); + sloReq.setNameID(userNameID); + userNameID.setFormat(nameIDFormat); + userNameID.setValue(nameID); + + String entityname = config.getPVP2IDPMetadataEntityName(); + if (MiscUtil.isEmpty(entityname)) { + log.info("No IDP EntityName configurated"); + throw new ConfigurationException("No IDP EntityName configurated"); + } + + //get IDP metadata from metadataprovider + HTTPMetadataProvider idpmetadata = config.getMetaDataProvier(); + EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname); + if (idpEntity == null) { + log.info("IDP EntityName is not found in IDP Metadata"); + throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); + } + + //select authentication-service url from metadata + SingleLogoutService redirectEndpoint = null; + for (SingleLogoutService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) { + + //Get the service address for the binding you wish to use + if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + redirectEndpoint = sss; + } + } + sloReq.setDestination(redirectEndpoint.getLocation()); + + //sign authentication request + KeyStore keyStore = config.getPVP2KeyStore(); + X509Credential authcredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreAuthRequestKeyAlias(), + config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(authcredential); + sloReq.setSignature(signer); + + //generate Http-POST Binding message + VelocityEngine engine = new VelocityEngine(); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + engine.setProperty("classpath.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, + "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); + engine.init(); + + HTTPPostEncoder encoder = new HTTPPostEncoder(engine, + "templates/pvp_postbinding_template.html"); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + response, true); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); + service.setLocation(redirectEndpoint.getLocation());; + + context.setOutboundSAMLMessageSigningCredential(authcredential); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloReq); + context.setOutboundMessageTransport(responseAdapter); + + encoder.encode(context); + + } catch (Exception e) { + log.warn("Authentication Request can not be generated", e); + throw new ServletException("Authentication Request can not be generated.", e); + } + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + process(request, response); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } + +} diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java index 832993604..05c253b6e 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java @@ -36,6 +36,7 @@ public class ApplicationBean implements Serializable { private boolean isLogin = false; private String errorMessage; + private String successMessage; /** * @return the familyName @@ -109,6 +110,18 @@ public class ApplicationBean implements Serializable { public void setLogin(boolean isLogin) { this.isLogin = isLogin; } + /** + * @return the successMessage + */ + public String getSuccessMessage() { + return successMessage; + } + /** + * @param successMessage the successMessage to set + */ + public void setSuccessMessage(String successMessage) { + this.successMessage = successMessage; + } diff --git a/id/oa/src/main/webapp/WEB-INF/web.xml b/id/oa/src/main/webapp/WEB-INF/web.xml index 85a1bbaeb..d40f156cd 100644 --- a/id/oa/src/main/webapp/WEB-INF/web.xml +++ b/id/oa/src/main/webapp/WEB-INF/web.xml @@ -8,7 +8,7 @@ pvp2login - pvp2login + PVP 2.1 Authentication request builder at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Authenticate @@ -17,6 +17,17 @@ /servlet/pvp2login + + pvp2slo + PVP 2.1 Single Log-Out request builder + at.gv.egovernment.moa.id.demoOA.servlet.pvp2.SingleLogOut + + + + pvp2slo + /servlet/startpvp2slo + + pvp2metadata Metadata @@ -39,5 +50,16 @@ /demoapplication + + index + Mainpage + at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Index + + + + index + /singlelogout + + -- cgit v1.2.3 From cc20e4171331f78a1bb188f2b885c9754da58a28 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 3 Jun 2014 17:09:42 +0200 Subject: update IDP single logout --- .../moa/id/data/SLOInformationContainer.java | 102 ++++++++++++++------- .../moa/id/protocols/pvp2x/MetadataAction.java | 58 ++++++------ .../moa/id/protocols/pvp2x/SingleLogOutAction.java | 12 ++- .../pvp2x/builder/SingleLogOutBuilder.java | 19 ++-- .../id/storage/AuthenticationSessionStoreage.java | 53 ++++++++--- 5 files changed, 161 insertions(+), 83 deletions(-) diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java index a0f3dd309..df195c0de 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java @@ -29,8 +29,10 @@ import java.util.LinkedHashMap; import java.util.List; import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.metadata.SingleLogoutService; +import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; @@ -52,47 +54,87 @@ public class SLOInformationContainer implements Serializable { public void parseActiveOAs(List dbOAs, String removeOAID) { - activeFrontChannalOAs = new LinkedHashMap(); - activeBackChannelOAs = new LinkedHashMap(); + if (activeBackChannelOAs == null) + activeBackChannelOAs = new LinkedHashMap(); + if (activeFrontChannalOAs == null) + activeFrontChannalOAs = new LinkedHashMap(); if (dbOAs != null) { for (OASessionStore oa : dbOAs) { - //Actually only PVP 2.1 support Single LogOut - if (PVP2XProtocol.NAME.equals(oa.getProtocolType()) && - !oa.getOaurlprefix().equals(removeOAID)) { + if (!oa.getOaurlprefix().equals(removeOAID)) { + + //Actually only PVP 2.1 support Single LogOut + if (PVP2XProtocol.PATH.equals(oa.getProtocolType())) { + SingleLogoutService sloDesc; + try { + sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(oa.getOaurlprefix()); + + if (sloDesc.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) + activeBackChannelOAs.put(oa.getOaurlprefix(), + new SLOInformationImpl( + oa.getAssertionSessionID(), + oa.getUserNameID(), + oa.getUserNameIDFormat(), + oa.getProtocolType(), + sloDesc)); + + else + activeFrontChannalOAs.put(oa.getOaurlprefix(), + new SLOInformationImpl( + oa.getAssertionSessionID(), + oa.getUserNameID(), + oa.getUserNameIDFormat(), + oa.getProtocolType(), + sloDesc)); + + } catch (NOSLOServiceDescriptorException e) { + putFailedOA(oa.getOaurlprefix()); + + } + + } else + putFailedOA(oa.getOaurlprefix()); + } + } + } + } + + /** + * @param dbIDPs + * @param value + */ + public void parseActiveIDPs(List dbIDPs, + String removeIDP) { + if (activeBackChannelOAs == null) + activeBackChannelOAs = new LinkedHashMap(); + if (activeFrontChannalOAs == null) + activeFrontChannalOAs = new LinkedHashMap(); + + if (dbIDPs != null) { + for (InterfederationSessionStore el : dbIDPs) { + if (!el.getIdpurlprefix().equals(removeIDP)) { + SingleLogoutService sloDesc; try { - sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(oa.getOaurlprefix()); - - if (sloDesc.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) - activeBackChannelOAs.put(oa.getOaurlprefix(), - new SLOInformationImpl( - oa.getAssertionSessionID(), - oa.getUserNameID(), - oa.getUserNameIDFormat(), - oa.getProtocolType(), - sloDesc)); + sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(el.getIdpurlprefix()); - else - activeFrontChannalOAs.put(oa.getOaurlprefix(), - new SLOInformationImpl( - oa.getAssertionSessionID(), - oa.getUserNameID(), - oa.getUserNameIDFormat(), - oa.getProtocolType(), + activeFrontChannalOAs.put(el.getIdpurlprefix(), + new SLOInformationImpl( + el.getSessionIndex(), + el.getUserNameID(), + NameID.TRANSIENT, + PVP2XProtocol.PATH, sloDesc)); } catch (NOSLOServiceDescriptorException e) { - putFailedOA(oa.getOaurlprefix()); + putFailedOA(el.getIdpurlprefix()); } - - } else - putFailedOA(oa.getOaurlprefix()); + } } } } - + public String getNextFrontChannelOA() { Iterator interator = activeFrontChannalOAs.keySet().iterator(); if (interator.hasNext()) @@ -147,9 +189,5 @@ public class SLOInformationContainer implements Serializable { if (sloFailedOAs == null) sloFailedOAs = new ArrayList(); sloFailedOAs.add(oaID); - } - - - - + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java index 01f7e18ba..c60e69df6 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java @@ -258,21 +258,21 @@ public class MetadataAction implements IAction { //add SLO descriptor -// SingleLogoutService postSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// postSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// postSLOService -// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); -// spSSODescriptor.getSingleLogoutServices().add(postSLOService); -// -// SingleLogoutService redirectSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// redirectSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// redirectSLOService -// .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); -// spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); + SingleLogoutService postSLOService = + SAML2Utils.createSAMLObject(SingleLogoutService.class); + postSLOService.setLocation(PVPConfiguration + .getInstance().getIDPSSOPostService()); + postSLOService + .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(postSLOService); + + SingleLogoutService redirectSLOService = + SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectSLOService.setLocation(PVPConfiguration + .getInstance().getIDPSSOPostService()); + redirectSLOService + .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); @@ -333,13 +333,13 @@ public class MetadataAction implements IAction { postSingleSignOnService); //add SLO descriptor -// SingleLogoutService postSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// postSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// postSLOService -// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); -// idpSSODescriptor.getSingleLogoutServices().add(postSLOService); + SingleLogoutService postSLOService = + SAML2Utils.createSAMLObject(SingleLogoutService.class); + postSLOService.setLocation(PVPConfiguration + .getInstance().getIDPSSOPostService()); + postSLOService + .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + idpSSODescriptor.getSingleLogoutServices().add(postSLOService); } @@ -355,13 +355,13 @@ public class MetadataAction implements IAction { redirectSingleSignOnService); //add SLO descriptor -// SingleLogoutService redirectSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// redirectSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// redirectSLOService -// .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); -// idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService); + SingleLogoutService redirectSLOService = + SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectSLOService.setLocation(PVPConfiguration + .getInstance().getIDPSSORedirectService()); + redirectSLOService + .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService); } /*if (PVPConfiguration.getInstance().getIDPResolveSOAPService() != null) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java index c67d10ab7..92441e663 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java @@ -42,6 +42,7 @@ import org.opensaml.xml.security.SecurityException; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; @@ -124,9 +125,11 @@ public class SingleLogOutAction implements IAction { } //store active OAs to SLOContaine - List dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); + List dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); + List dbIDPs = AuthenticationSessionStoreage.getAllActiveIDPsFromMOASession(session); SLOInformationContainer sloContainer = new SLOInformationContainer(); sloContainer.setSloRequest(pvpReq); + sloContainer.parseActiveIDPs(dbIDPs, logOutReq.getIssuer().getValue()); sloContainer.parseActiveOAs(dbOAs, logOutReq.getIssuer().getValue()); //terminate MOASession @@ -247,10 +250,13 @@ public class SingleLogOutAction implements IAction { private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { Status status = logOutResp.getStatus(); - if (!status.getStatusCode().equals(StatusCode.SUCCESS_URI)) { + if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + String message = " Message: "; + if (status.getStatusMessage() != null) + message += status.getStatusMessage().getMessage(); Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() - + " Message: " + status.getStatusMessage().getMessage() + ")"); + + message + ")"); sloContainer.putFailedOA(logOutResp.getIssuer().getValue()); } else diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java index 04d374e93..7aa860c5c 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java @@ -35,6 +35,7 @@ import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.StatusMessage; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.SSODescriptor; import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.provider.MetadataProviderException; @@ -125,7 +126,7 @@ public class SingleLogOutBuilder { public static SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException { try { EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID); - SPSSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + SSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); SingleLogoutService sloService = null; for (SingleLogoutService el : spsso.getSingleLogoutServices()) { @@ -173,14 +174,18 @@ public class SingleLogOutBuilder { if (el.getBinding().equals(spRequest.getBinding())) sloService = el; } - if (sloService == null && spsso.getSingleLogoutServices().size() != 0) - sloService = spsso.getSingleLogoutServices().get(0); - else { - Logger.error("Found no SLO ServiceDescriptor in Metadata"); - throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null); + if (sloService == null) { + if (spsso.getSingleLogoutServices().size() != 0) + sloService = spsso.getSingleLogoutServices().get(0); + + else { + Logger.error("Found no SLO ServiceDescriptor in Metadata"); + throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null); + } } - return sloService; + + return sloService; } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java index 6c2900752..5daca0888 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java @@ -64,7 +64,7 @@ public class AuthenticationSessionStoreage { AuthenticatedSessionStore session; try { - session = searchInDatabase(moaSessionID); + session = searchInDatabase(moaSessionID, true); return session.isAuthenticated(); } catch (MOADatabaseException e) { @@ -102,7 +102,7 @@ public class AuthenticationSessionStoreage { public static AuthenticationSession getSession(String sessionID) throws MOADatabaseException { try { - AuthenticatedSessionStore dbsession = searchInDatabase(sessionID); + AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true); return decryptSession(dbsession); } catch (MOADatabaseException e) { @@ -122,7 +122,7 @@ public class AuthenticationSessionStoreage { public static void storeSession(AuthenticationSession session, String pendingRequestID) throws MOADatabaseException, BuildException { try { - AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID()); + AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID(), true); if (MiscUtil.isNotEmpty(pendingRequestID)) dbsession.setPendingRequestID(pendingRequestID); @@ -175,7 +175,7 @@ public class AuthenticationSessionStoreage { throws AuthenticationException, BuildException { try { - AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID()); + AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID(), true); String id = Random.nextRandom(); @@ -207,7 +207,7 @@ public class AuthenticationSessionStoreage { AuthenticatedSessionStore session; try { - session = searchInDatabase(moaSessionID); + session = searchInDatabase(moaSessionID, true); session.setAuthenticated(value); MOASessionDBUtils.saveOrUpdate(session); @@ -249,7 +249,7 @@ public class AuthenticationSessionStoreage { public static boolean isSSOSession(String sessionID) throws MOADatabaseException { try { - AuthenticatedSessionStore dbsession = searchInDatabase(sessionID); + AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true); return dbsession.isSSOSession(); } catch (MOADatabaseException e) { @@ -391,8 +391,36 @@ public class AuthenticationSessionStoreage { MiscUtil.assertNotNull(moaSession, "MOASession"); try { - AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID()); - return dbsession.getActiveOAsessions(); + List oas = new ArrayList(); + + AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID(), false); + oas.addAll(dbsession.getActiveOAsessions()); + + Session session = MOASessionDBUtils.getCurrentSession(); + session.getTransaction().commit(); + + return oas; + + } catch (MOADatabaseException e) { + Logger.warn("NO session information found for sessionID " + moaSession.getSessionID(), e); + + } + + return null; + } + + public static List getAllActiveIDPsFromMOASession(AuthenticationSession moaSession) { + MiscUtil.assertNotNull(moaSession, "MOASession"); + + try { + List idps = new ArrayList(); + AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID(), false); + idps.addAll(dbsession.getInderfederation()); + + Session session = MOASessionDBUtils.getCurrentSession(); + session.getTransaction().commit(); + + return idps; } catch (MOADatabaseException e) { Logger.warn("NO session information found for sessionID " + moaSession.getSessionID(), e); @@ -475,7 +503,7 @@ public class AuthenticationSessionStoreage { public static String getPendingRequestID(String sessionID) { try { - AuthenticatedSessionStore dbsession = searchInDatabase(sessionID); + AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true); return dbsession.getPendingRequestID(); } catch (MOADatabaseException e) { @@ -654,7 +682,7 @@ public class AuthenticationSessionStoreage { String moaSession = getMOASessionSSOID(ssoID); if (MiscUtil.isNotEmpty(moaSession)) { try { - dbsession = searchInDatabase(moaSession); + dbsession = searchInDatabase(moaSession, true); }catch (MOADatabaseException e) { @@ -889,7 +917,7 @@ public class AuthenticationSessionStoreage { } @SuppressWarnings("rawtypes") - private static AuthenticatedSessionStore searchInDatabase(String sessionID) throws MOADatabaseException { + private static AuthenticatedSessionStore searchInDatabase(String sessionID, boolean commit) throws MOADatabaseException { MiscUtil.assertNotNull(sessionID, "moasessionID"); Logger.trace("Get authenticated session with sessionID " + sessionID + " from database."); Session session = MOASessionDBUtils.getCurrentSession(); @@ -903,7 +931,8 @@ public class AuthenticationSessionStoreage { result = query.list(); //send transaction - session.getTransaction().commit(); + if (commit) + session.getTransaction().commit(); } Logger.trace("Found entries: " + result.size()); -- cgit v1.2.3 From 78c78fc0045580d3456fcb9563209223cf425eb6 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 3 Jun 2014 17:10:11 +0200 Subject: implement configuration tool single logout --- .../moa/id/configuration/Constants.java | 9 + .../id/configuration/auth/AuthenticatedUser.java | 28 +- .../configuration/auth/AuthenticationManager.java | 84 +++++ .../id/configuration/auth/IActiveUserStorage.java | 35 ++ .../auth/MemoryActiveUserStorageImpl.java | 71 +++++ .../id/configuration/auth/pvp2/Authenticate.java | 260 --------------- .../id/configuration/auth/pvp2/BuildMetadata.java | 336 ------------------- .../moa/id/configuration/auth/pvp2/PVP2Utils.java | 232 ++++++++++++++ .../auth/pvp2/servlets/Authenticate.java | 231 ++++++++++++++ .../auth/pvp2/servlets/BuildMetadata.java | 355 +++++++++++++++++++++ .../auth/pvp2/servlets/SLOBackChannelServlet.java | 159 +++++++++ .../auth/pvp2/servlets/SLOBasicServlet.java | 271 ++++++++++++++++ .../auth/pvp2/servlets/SLOFrontChannelServlet.java | 287 +++++++++++++++++ .../config/ConfigurationProvider.java | 8 +- .../id/configuration/exception/PVP2Exception.java | 55 ++++ .../id/configuration/exception/SLOException.java | 53 +++ .../configuration/filter/AuthenticationFilter.java | 47 ++- .../id/configuration/helper/FormDataHelper.java | 2 +- .../configuration/struts/action/IndexAction.java | 95 +++--- .../resources/applicationResources_de.properties | 3 + .../resources/applicationResources_en.properties | 3 + id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml | 26 +- 22 files changed, 1980 insertions(+), 670 deletions(-) create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java delete mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java delete mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java create mode 100644 id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java index df1faa7c0..61880b0cb 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java @@ -35,6 +35,9 @@ public class Constants { public static final String SERVLET_PVP2ASSERTION = "pvp2login.action"; public static final String SERVLET_ACCOUNTVERIFICATION = "mailAddressVerification.action"; + public static final String SERVLET_LOGOUT = "logout.action"; + public static final String SERVLET_SLO_FRONT = "servlet/sloFrontChannel"; + public static final String SERVLET_SLO_BACK = "servlet/sloBackChannel"; public static final String STRUTS_SUCCESS = "success"; public static final String STRUTS_ERROR = "error"; @@ -58,6 +61,9 @@ public class Constants { public static final String SESSION_SENDASSERTIONTEMPLATE = "sendAssertionTemplate"; public static final String SESSION_SLTRANSFORMATION = "slTransformation"; + public static final String SESSION_SLOERROR = "sloerrormessage"; + public static final String SESSION_SLOSUCCESS = "slosuccessmessage"; + public static final String SESSION_I18n = "WW_TRANS_I18N_LOCALE"; @@ -69,6 +75,8 @@ public class Constants { public static final String REQUEST_FORMCUSTOM_MODULE = "module"; public static final String REQUEST_FORMCUSTOM_VALUE = "value"; + public static final String REQUEST_USERSLO = "userLogOut"; + public static final String BKU_ONLINE = "bkuonline"; public static final String BKU_LOCAL = "bkulocal"; public static final String BKU_HANDY = "bkuhandy"; @@ -97,6 +105,7 @@ public class Constants { public static final Map BUSINESSSERVICENAMES; + static { Hashtable tmp = new Hashtable(); tmp.put(IDENIFICATIONTYPE_FN, "Firmenbuchnummer"); diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java index 330ed7036..036acf1f6 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java @@ -47,6 +47,9 @@ public class AuthenticatedUser { private String businessServiceType; private String businessServiceNumber; + private String nameID = null; + private String nameIDFormat = null; + private AuthenticatedUser() { } @@ -68,7 +71,8 @@ public class AuthenticatedUser { return user; } - public static AuthenticatedUser generateUserRequestUser(UserDatabaseFrom form) { + public static AuthenticatedUser generateUserRequestUser(UserDatabaseFrom form, + String nameID, String nameIDFormat) { AuthenticatedUser user = new AuthenticatedUser(); user.familyName = form.getFamilyName(); @@ -82,11 +86,14 @@ public class AuthenticatedUser { user.isPVP2Login = form.isPVPGenerated(); user.lastLogin = new Date(); + user.nameID = nameID; + user.nameIDFormat = nameIDFormat; + return user; } public AuthenticatedUser(UserDatabase userdb, boolean isAuthenticated, boolean isMandateUser, - boolean isPVP2Login) { + boolean isPVP2Login, String nameID, String nameIDFormat) { this.familyName = userdb.getFamilyname(); this.givenName = userdb.getGivenname(); @@ -99,6 +106,9 @@ public class AuthenticatedUser { this.isPVP2Login = isPVP2Login; this.lastLogin = new Date(); + this.nameID = nameID; + this.nameIDFormat = nameIDFormat; + if (!this.isAdmin) generateUserSpecificConfigurationOptions(userdb); } @@ -226,6 +236,20 @@ public class AuthenticatedUser { public void setLastLogin(Date lastLogin) { this.lastLogin = lastLogin; } + + /** + * @return the nameID + */ + public String getNameID() { + return nameID; + } + + /** + * @return the nameIDFormat + */ + public String getNameIDFormat() { + return nameIDFormat; + } diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java new file mode 100644 index 000000000..6d3afffc9 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java @@ -0,0 +1,84 @@ +/* + * 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.configuration.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author tlenz + * + */ +public class AuthenticationManager { + + private static final Logger log = LoggerFactory + .getLogger(AuthenticationManager.class); + + private static AuthenticationManager instance = null; + private static IActiveUserStorage activeUsers = null; + + public static AuthenticationManager getInstance() { + if (instance == null) + instance = new AuthenticationManager(); + + return instance; + } + + private AuthenticationManager() { + activeUsers = new MemoryActiveUserStorageImpl(); + + } + + public AuthenticatedUser getActiveUser(String nameID) { + return activeUsers.getUser(nameID); + } + + public void setActiveUser(AuthenticatedUser authUser) { + log.debug("LogIn user with nameID:" + authUser.getNameID()); + activeUsers.setUser(authUser.getNameID(), authUser); + + } + + public boolean isActiveUser(String nameID) { + AuthenticatedUser user = activeUsers.getUser(nameID); + if (user != null && user.isAuthenticated()) + return true; + else + return false; + } + + public boolean isActiveUser(AuthenticatedUser authUser) { + if (authUser != null) + return isActiveUser(authUser.getNameID()); + else + return false; + } + + public void removeActiveUser(AuthenticatedUser authUser) { + log.debug("LogOut active user " + authUser.getGivenName() + " " + authUser.getFamilyName() + + " dbID: " + authUser.getUserID() + " nameID:" + authUser.getNameID()); + activeUsers.removeUser(authUser.getNameID()); + + } +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java new file mode 100644 index 000000000..c52fee140 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java @@ -0,0 +1,35 @@ +/* + * 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.configuration.auth; + +/** + * @author tlenz + * + */ +public interface IActiveUserStorage { + + public AuthenticatedUser getUser(String nameID); + public void setUser(String nameID, AuthenticatedUser authUser); + public void removeUser(String nameID); + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java new file mode 100644 index 000000000..145da2c35 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java @@ -0,0 +1,71 @@ +/* + * 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.configuration.auth; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author tlenz + * + */ +public class MemoryActiveUserStorageImpl implements IActiveUserStorage { + + private Map store = null; + + /** + * + */ + public MemoryActiveUserStorageImpl() { + store = new HashMap(); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#getUser(java.lang.String) + */ + @Override + public AuthenticatedUser getUser(String nameID) { + return store.get(nameID); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#setUser(java.lang.String, at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser) + */ + @Override + public void setUser(String nameID, AuthenticatedUser authUser) { + store.put(nameID, authUser); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#removeUser(java.lang.String) + */ + @Override + public void removeUser(String nameID) { + if (store.containsKey(nameID)) + store.remove(nameID); + + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java deleted file mode 100644 index abcfd67e9..000000000 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************* - * 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.configuration.auth.pvp2; - -import java.io.IOException; -import java.security.KeyStore; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; - -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.runtime.RuntimeConstants; -import org.joda.time.DateTime; -import org.opensaml.Configuration; -import org.opensaml.common.SAMLObject; -import org.opensaml.common.binding.BasicSAMLMessageContext; -import org.opensaml.common.impl.SecureRandomIdentifierGenerator; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.NameIDPolicy; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml2.core.Subject; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SingleSignOnService; -import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; -import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; -import org.opensaml.ws.transport.http.HttpServletResponseAdapter; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.io.Marshaller; -import org.opensaml.xml.io.MarshallingException; -import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.Signature; -import org.opensaml.xml.signature.SignatureConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; - -import at.gv.egovernment.moa.id.configuration.Constants; -import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; -import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; -import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; -import at.gv.egovernment.moa.util.MiscUtil; - - -/** - * Servlet implementation class Authenticate - */ -public class Authenticate extends HttpServlet { - private static final long serialVersionUID = 1L; - - private static final Logger log = LoggerFactory - .getLogger(Authenticate.class); - /** - * @see HttpServlet#HttpServlet() - */ - public Authenticate() { - super(); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - try { - builder = factory.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - log.warn("PVP2 AuthenticationServlet can not be initialized.", e); - - } - } - - DocumentBuilder builder; - - public Document asDOMDocument(XMLObject object) throws IOException, - MarshallingException, TransformerException { - Document document = builder.newDocument(); - Marshaller out = Configuration.getMarshallerFactory().getMarshaller( - object); - out.marshall(object, document); - return document; - } - - protected void process(HttpServletRequest request, - HttpServletResponse response, Map legacyParameter) throws ServletException, IOException { - try { - - ConfigurationProvider config = ConfigurationProvider.getInstance(); - config.initializePVP2Login(); - - AuthnRequest authReq = SAML2Utils - .createSAMLObject(AuthnRequest.class); - SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); - authReq.setID(gen.generateIdentifier()); - - HttpSession session = request.getSession(); - if (session != null) { - session.setAttribute(Constants.SESSION_PVP2REQUESTID, authReq.getID()); - } - - authReq.setAssertionConsumerServiceIndex(0); - authReq.setAttributeConsumingServiceIndex(0); - authReq.setIssueInstant(new DateTime()); - Subject subject = SAML2Utils.createSAMLObject(Subject.class); - NameID name = SAML2Utils.createSAMLObject(NameID.class); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - - String serviceURL = config.getPublicUrlPreFix(request); - if (!serviceURL.endsWith("/")) - serviceURL = serviceURL + "/"; - name.setValue(serviceURL); - issuer.setValue(serviceURL); - - subject.setNameID(name); - authReq.setSubject(subject); - issuer.setFormat(NameIDType.ENTITY); - authReq.setIssuer(issuer); - NameIDPolicy policy = SAML2Utils - .createSAMLObject(NameIDPolicy.class); - policy.setAllowCreate(true); - policy.setFormat(NameID.PERSISTENT); - authReq.setNameIDPolicy(policy); - - String entityname = config.getPVP2IDPMetadataEntityName(); - if (MiscUtil.isEmpty(entityname)) { - log.info("No IDP EntityName configurated"); - throw new ConfigurationException("No IDP EntityName configurated"); - } - - HTTPMetadataProvider idpmetadata = config.getMetaDataProvier(); - EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname); - if (idpEntity == null) { - log.info("IDP EntityName is not found in IDP Metadata"); - throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); - } - - SingleSignOnService redirectEndpoint = null; - for (SingleSignOnService sss : - idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { - - //Get the service address for the binding you wish to use - if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { - redirectEndpoint = sss; - } - } - - authReq.setDestination(redirectEndpoint.getLocation()); - - RequestedAuthnContext reqAuthContext = - SAML2Utils.createSAMLObject(RequestedAuthnContext.class); - - AuthnContextClassRef authnClassRef = - SAML2Utils.createSAMLObject(AuthnContextClassRef.class); - - authnClassRef.setAuthnContextClassRef("http://www.stork.gov.eu/1.0/citizenQAALevel/4"); - - reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); - - reqAuthContext.getAuthnContextClassRefs().add(authnClassRef); - - authReq.setRequestedAuthnContext(reqAuthContext); - - KeyStore keyStore = config.getPVP2KeyStore(); - - X509Credential authcredential = new KeyStoreX509CredentialAdapter( - keyStore, - config.getPVP2KeystoreAuthRequestKeyAlias(), - config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); - - Signature signer = SAML2Utils.createSAMLObject(Signature.class); - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); - signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); - signer.setSigningCredential(authcredential); - - authReq.setSignature(signer); - - VelocityEngine engine = new VelocityEngine(); - engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); - engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); - engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); - engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); - engine.setProperty("classpath.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); - engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, - "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); - engine.init(); - - HTTPPostEncoder encoder = new HTTPPostEncoder(engine, - "templates/pvp_postbinding_template.html"); - HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( - response, true); - BasicSAMLMessageContext context = new BasicSAMLMessageContext(); - SingleSignOnService service = new SingleSignOnServiceBuilder() - .buildObject(); - service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); - service.setLocation(redirectEndpoint.getLocation());; - - context.setOutboundSAMLMessageSigningCredential(authcredential); - context.setPeerEntityEndpoint(service); - context.setOutboundSAMLMessage(authReq); - context.setOutboundMessageTransport(responseAdapter); - - encoder.encode(context); - - } catch (Exception e) { - log.warn("Authentication Request can not be generated", e); - throw new ServletException("Authentication Request can not be generated.", e); - } - } - - /** - * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse - * response) - */ - protected void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - - process(request, response, null); - } - - /** - * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse - * response) - */ - protected void doPost(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - process(request, response, null); - } - -} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java deleted file mode 100644 index 9a0f73a1f..000000000 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java +++ /dev/null @@ -1,336 +0,0 @@ -/******************************************************************************* - * 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.configuration.auth.pvp2; - -import java.io.IOException; -import java.io.StringWriter; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.apache.log4j.Logger; -import org.joda.time.DateTime; -import org.opensaml.Configuration; -import org.opensaml.common.impl.SecureRandomIdentifierGenerator; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.KeyDescriptor; -import org.opensaml.saml2.metadata.LocalizedString; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.ServiceName; -import org.opensaml.xml.io.Marshaller; -import org.opensaml.xml.io.MarshallingException; -import org.opensaml.xml.security.SecurityException; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; -import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; -import org.opensaml.xml.signature.Signature; -import org.opensaml.xml.signature.SignatureConstants; -import org.opensaml.xml.signature.SignatureException; -import org.opensaml.xml.signature.Signer; -import org.w3c.dom.Document; - -import at.gv.egovernment.moa.id.configuration.Constants; -import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; -import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; -import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; -import at.gv.egovernment.moa.util.MiscUtil; - -/** - * Servlet implementation class BuildMetadata - */ -public class BuildMetadata extends HttpServlet { - private static final long serialVersionUID = 1L; - - private static final Logger log = Logger.getLogger(BuildMetadata.class); - - private static final int VALIDUNTIL_IN_HOURS = 24; - - /** - * @see HttpServlet#HttpServlet() - */ - public BuildMetadata() { - super(); - } - - protected static Signature getSignature(Credential credentials) { - Signature signer = SAML2Utils.createSAMLObject(Signature.class); - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); - signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); - signer.setSigningCredential(credentials); - return signer; - } - - /** - * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse - * response) - */ - protected void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - try { - ConfigurationProvider config = ConfigurationProvider.getInstance(); - - //config.initializePVP2Login(); - - SecureRandomIdentifierGenerator idGen = new SecureRandomIdentifierGenerator(); - - EntitiesDescriptor spEntitiesDescriptor = SAML2Utils. - createSAMLObject(EntitiesDescriptor.class); - - DateTime date = new DateTime(); - spEntitiesDescriptor.setValidUntil(date.plusHours(VALIDUNTIL_IN_HOURS)); - - String name = config.getPVP2MetadataEntitiesName(); - if (MiscUtil.isEmpty(name)) { - log.info("NO Metadata EntitiesName configurated"); - throw new ConfigurationException("NO Metadata EntitiesName configurated"); - } - - spEntitiesDescriptor.setName(name); - spEntitiesDescriptor.setID(idGen.generateIdentifier()); - - EntityDescriptor spEntityDescriptor = SAML2Utils - .createSAMLObject(EntityDescriptor.class); - - spEntityDescriptor.setValidUntil(date.plusDays(VALIDUNTIL_IN_HOURS)); - - spEntitiesDescriptor.getEntityDescriptors().add(spEntityDescriptor); - - String serviceURL = config.getPublicUrlPreFix(request); - if (!serviceURL.endsWith("/")) - serviceURL = serviceURL + "/"; - - log.debug("Set OnlineApplicationURL to " + serviceURL); - spEntityDescriptor.setEntityID(serviceURL); - - SPSSODescriptor spSSODescriptor = SAML2Utils - .createSAMLObject(SPSSODescriptor.class); - - spSSODescriptor.setAuthnRequestsSigned(true); - spSSODescriptor.setWantAssertionsSigned(true); - - X509KeyInfoGeneratorFactory keyInfoFactory = new X509KeyInfoGeneratorFactory(); - keyInfoFactory.setEmitEntityCertificate(true); - KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); - - KeyStore keyStore = config.getPVP2KeyStore(); - - X509Credential signingcredential = new KeyStoreX509CredentialAdapter( - keyStore, - config.getPVP2KeystoreMetadataKeyAlias(), - config.getPVP2KeystoreMetadataKeyPassword().toCharArray()); - - - log.debug("Set Metadata key information"); - //Set MetaData Signing key - KeyDescriptor entitiesSignKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - entitiesSignKeyDescriptor.setUse(UsageType.SIGNING); - entitiesSignKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(signingcredential)); - Signature entitiesSignature = getSignature(signingcredential); - spEntitiesDescriptor.setSignature(entitiesSignature); - - //Set AuthRequest Signing certificate - X509Credential authcredential = new KeyStoreX509CredentialAdapter( - keyStore, - config.getPVP2KeystoreAuthRequestKeyAlias(), - config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); - KeyDescriptor signKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - signKeyDescriptor.setUse(UsageType.SIGNING); - signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential)); - spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); - - - //set AuthRequest encryption certificate - if (MiscUtil.isNotEmpty(config.getPVP2KeystoreAuthRequestEncryptionKeyAlias())) { - X509Credential authEncCredential = new KeyStoreX509CredentialAdapter( - keyStore, - config.getPVP2KeystoreAuthRequestEncryptionKeyAlias(), - config.getPVP2KeystoreAuthRequestEncryptionKeyPassword().toCharArray()); - KeyDescriptor encryKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - encryKeyDescriptor.setUse(UsageType.ENCRYPTION); - encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential)); - spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor); - - } else { - log.warn("No Assertion Encryption-Key defined. This setting is not recommended!"); - - } - - - NameIDFormat persistentnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - persistentnameIDFormat.setFormat(NameIDType.PERSISTENT); - - spSSODescriptor.getNameIDFormats().add(persistentnameIDFormat); - - NameIDFormat transientnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - transientnameIDFormat.setFormat(NameIDType.TRANSIENT); - - spSSODescriptor.getNameIDFormats().add(transientnameIDFormat); - - NameIDFormat unspecifiednameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - unspecifiednameIDFormat.setFormat(NameIDType.UNSPECIFIED); - - spSSODescriptor.getNameIDFormats().add(unspecifiednameIDFormat); - - AssertionConsumerService postassertionConsumerService = - SAML2Utils.createSAMLObject(AssertionConsumerService.class); - - postassertionConsumerService.setIndex(0); - postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION); - - spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); - - spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); - - spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor); - - spSSODescriptor.setWantAssertionsSigned(true); - spSSODescriptor.setAuthnRequestsSigned(true); - - AttributeConsumingService attributeService = - SAML2Utils.createSAMLObject(AttributeConsumingService.class); - - attributeService.setIndex(0); - attributeService.setIsDefault(true); - ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class); - serviceName.setName(new LocalizedString("Default Service", "de")); - attributeService.getNames().add(serviceName); - - attributeService.getRequestAttributes().addAll(AttributeListBuilder.getRequestedAttributes()); - - spSSODescriptor.getAttributeConsumingServices().add(attributeService); - - DocumentBuilder builder; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - - builder = factory.newDocumentBuilder(); - Document document = builder.newDocument(); - Marshaller out = Configuration.getMarshallerFactory().getMarshaller(spEntitiesDescriptor); - out.marshall(spEntitiesDescriptor, document); - - Signer.signObject(entitiesSignature); - - Transformer transformer = TransformerFactory.newInstance().newTransformer(); - - StringWriter sw = new StringWriter(); - StreamResult sr = new StreamResult(sw); - DOMSource source = new DOMSource(document); - transformer.transform(source, sr); - sw.close(); - - String metadataXML = sw.toString(); - - response.setContentType("text/xml"); - response.getOutputStream().write(metadataXML.getBytes()); - - response.getOutputStream().close(); - - } catch (ConfigurationException e) { - log.warn("Configuration can not be loaded.", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (NoSuchAlgorithmException e) { - log.warn("Requested Algorithm could not found.", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (KeyStoreException e) { - log.warn("Requested KeyStoreType is not implemented.", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (CertificateException e) { - log.warn("KeyStore can not be opend or userd.", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (SecurityException e) { - log.warn("KeyStore can not be opend or used", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (ParserConfigurationException e) { - log.warn("PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (MarshallingException e) { - log.warn("PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (SignatureException e) { - log.warn("PVP2 Metadata can not be signed", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (TransformerConfigurationException e) { - log.warn("PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (TransformerFactoryConfigurationError e) { - log.warn("PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - - } catch (TransformerException e) { - log.warn("PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - } - - catch (Exception e) { - log.warn("Unspecific PVP2 Metadata createn error", e); - throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); - } - - } - - /** - * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse - * response) - */ - protected void doPost(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - } - -} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java new file mode 100644 index 000000000..5032222d0 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java @@ -0,0 +1,232 @@ +/* + * 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.configuration.auth.pvp2; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.SignableSAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.security.MetadataCredentialResolver; +import org.opensaml.security.MetadataCredentialResolverFactory; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; +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.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; +import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.AbstractSignableXMLObject; +import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; +import org.opensaml.xml.validation.ValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; +import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception; +import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; + +/** + * @author tlenz + * + */ +public class PVP2Utils { + + private static final Logger log = LoggerFactory + .getLogger(PVP2Utils.class); + + public static void postBindingEncoder(HttpServletRequest req, HttpServletResponse resp, + SignableSAMLObject pvp2Req, X509Credential authcredential, String targetLocation, String relayState) throws PVP2Exception { + try { + VelocityEngine engine = new VelocityEngine(); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + engine.setProperty("classpath.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, + "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); + engine.init(); + + HTTPPostEncoder encoder = new HTTPPostEncoder(engine, + "templates/pvp_postbinding_template.html"); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + resp, true); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + service.setLocation(targetLocation); + + context.setOutboundSAMLMessageSigningCredential(authcredential); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(pvp2Req); + context.setOutboundMessageTransport(responseAdapter); + context.setRelayState(relayState); + + encoder.encode(context); + + } catch (MessageEncodingException e) { + log.warn("Encode PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Encode PVP 2.1 message FAILED.", e); + + } + } + + + /** + * @param request + * @param response + * @param sloReq + * @param authcredential + * @param location + * @param object + * @throws PVP2Exception + */ + public static void redirectBindingEncoder(HttpServletRequest request, + HttpServletResponse response, SignableSAMLObject pvp2Req, + X509Credential authcredential, String location, String relayState) throws PVP2Exception { + try { + HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + response + , true); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + service.setLocation(location); + context.setOutboundSAMLMessageSigningCredential(authcredential); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(pvp2Req); + context.setOutboundMessageTransport(responseAdapter); + context.setRelayState(relayState); + + encoder.encode(context); + } catch (MessageEncodingException e) { + log.warn("Encode PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Encode PVP 2.1 message FAILED.", e); + + } + } + + public static void validateSignature(SignableXMLObject msg, ConfigurationProvider configuration) throws SecurityException, ValidationException { + //Validate Signature + SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + profileValidator.validate(msg.getSignature()); + + //Verify Signature + List keyInfoProvider = new ArrayList(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + + KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); + MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier()); + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityIDCriteria(configuration.getPVP2IDPMetadataEntityName())); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); + trustEngine.validate(msg.getSignature(), criteriaSet); + } + + public static X509Credential signMessage(AbstractSignableXMLObject msg, ConfigurationProvider config) throws PVP2Exception { + //sign authentication request + KeyStore keyStore; + try { + keyStore = config.getPVP2KeyStore(); + X509Credential authcredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreAuthRequestKeyAlias(), + config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(authcredential); + msg.setSignature(signer); + + return authcredential; + + } catch (NoSuchAlgorithmException e) { + log.warn("Sign PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e); + + } catch (CertificateException e) { + log.warn("Sign PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e); + + } catch (KeyStoreException e) { + log.warn("Sign PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e); + + } catch (ConfigurationException e) { + log.warn("Sign PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e); + + } catch (IOException e) { + log.warn("Sign PVP 2.1 message FAILED.", e); + throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e); + } + } +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java new file mode 100644 index 000000000..56f6d8827 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * 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.configuration.auth.pvp2.servlets; + +import java.io.IOException; +import java.security.KeyStore; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.joda.time.DateTime; +import org.opensaml.Configuration; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDPolicy; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.core.Subject; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.AbstractSignableXMLObject; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.id.configuration.Constants; +import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils; +import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; +import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; +import at.gv.egovernment.moa.util.MiscUtil; + + +/** + * Servlet implementation class Authenticate + */ +public class Authenticate extends HttpServlet { + private static final long serialVersionUID = 1L; + + private static final Logger log = LoggerFactory + .getLogger(Authenticate.class); + /** + * @see HttpServlet#HttpServlet() + */ + public Authenticate() { + super(); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + log.warn("PVP2 AuthenticationServlet can not be initialized.", e); + + } + } + + DocumentBuilder builder; + + public Document asDOMDocument(XMLObject object) throws IOException, + MarshallingException, TransformerException { + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory().getMarshaller( + object); + out.marshall(object, document); + return document; + } + + protected void process(HttpServletRequest request, + HttpServletResponse response, Map legacyParameter) throws ServletException, IOException { + try { + + ConfigurationProvider config = ConfigurationProvider.getInstance(); + config.initializePVP2Login(); + + AuthnRequest authReq = SAML2Utils + .createSAMLObject(AuthnRequest.class); + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + authReq.setID(gen.generateIdentifier()); + + HttpSession session = request.getSession(); + if (session != null) { + session.setAttribute(Constants.SESSION_PVP2REQUESTID, authReq.getID()); + } + + authReq.setAssertionConsumerServiceIndex(0); + authReq.setAttributeConsumingServiceIndex(0); + authReq.setIssueInstant(new DateTime()); + Subject subject = SAML2Utils.createSAMLObject(Subject.class); + NameID name = SAML2Utils.createSAMLObject(NameID.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + name.setValue(serviceURL); + issuer.setValue(serviceURL); + + subject.setNameID(name); + authReq.setSubject(subject); + issuer.setFormat(NameIDType.ENTITY); + authReq.setIssuer(issuer); + NameIDPolicy policy = SAML2Utils + .createSAMLObject(NameIDPolicy.class); + policy.setAllowCreate(true); + policy.setFormat(NameID.PERSISTENT); + authReq.setNameIDPolicy(policy); + + String entityname = config.getPVP2IDPMetadataEntityName(); + if (MiscUtil.isEmpty(entityname)) { + log.info("No IDP EntityName configurated"); + throw new ConfigurationException("No IDP EntityName configurated"); + } + + HTTPMetadataProvider idpmetadata = config.getMetaDataProvier(); + EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname); + if (idpEntity == null) { + log.info("IDP EntityName is not found in IDP Metadata"); + throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); + } + + SingleSignOnService redirectEndpoint = null; + for (SingleSignOnService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { + + //Get the service address for the binding you wish to use + if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + redirectEndpoint = sss; + } + } + + authReq.setDestination(redirectEndpoint.getLocation()); + + RequestedAuthnContext reqAuthContext = + SAML2Utils.createSAMLObject(RequestedAuthnContext.class); + + AuthnContextClassRef authnClassRef = + SAML2Utils.createSAMLObject(AuthnContextClassRef.class); + + authnClassRef.setAuthnContextClassRef("http://www.stork.gov.eu/1.0/citizenQAALevel/4"); + + reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); + + reqAuthContext.getAuthnContextClassRefs().add(authnClassRef); + + authReq.setRequestedAuthnContext(reqAuthContext); + + //sign Message + X509Credential authcredential = PVP2Utils.signMessage((AbstractSignableXMLObject) authReq, config); + + //encode message + PVP2Utils.postBindingEncoder(request, + response, + authReq, + authcredential, + redirectEndpoint.getLocation(), + null); + + } catch (Exception e) { + log.warn("Authentication Request can not be generated", e); + throw new ServletException("Authentication Request can not be generated.", e); + } + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + process(request, response, null); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + process(request, response, null); + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java new file mode 100644 index 000000000..5265aed86 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * 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.configuration.auth.pvp2.servlets; + +import java.io.IOException; +import java.io.StringWriter; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.opensaml.Configuration; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml2.metadata.LocalizedString; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.ServiceName; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.SignatureException; +import org.opensaml.xml.signature.Signer; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.id.configuration.Constants; +import at.gv.egovernment.moa.id.configuration.auth.pvp2.AttributeListBuilder; +import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; +import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * Servlet implementation class BuildMetadata + */ +public class BuildMetadata extends HttpServlet { + private static final long serialVersionUID = 1L; + + private static final Logger log = Logger.getLogger(BuildMetadata.class); + + private static final int VALIDUNTIL_IN_HOURS = 24; + + /** + * @see HttpServlet#HttpServlet() + */ + public BuildMetadata() { + super(); + } + + protected static Signature getSignature(Credential credentials) { + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(credentials); + return signer; + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + try { + ConfigurationProvider config = ConfigurationProvider.getInstance(); + + //config.initializePVP2Login(); + + SecureRandomIdentifierGenerator idGen = new SecureRandomIdentifierGenerator(); + + EntitiesDescriptor spEntitiesDescriptor = SAML2Utils. + createSAMLObject(EntitiesDescriptor.class); + + DateTime date = new DateTime(); + spEntitiesDescriptor.setValidUntil(date.plusHours(VALIDUNTIL_IN_HOURS)); + + String name = config.getPVP2MetadataEntitiesName(); + if (MiscUtil.isEmpty(name)) { + log.info("NO Metadata EntitiesName configurated"); + throw new ConfigurationException("NO Metadata EntitiesName configurated"); + } + + spEntitiesDescriptor.setName(name); + spEntitiesDescriptor.setID(idGen.generateIdentifier()); + + EntityDescriptor spEntityDescriptor = SAML2Utils + .createSAMLObject(EntityDescriptor.class); + + spEntityDescriptor.setValidUntil(date.plusDays(VALIDUNTIL_IN_HOURS)); + + spEntitiesDescriptor.getEntityDescriptors().add(spEntityDescriptor); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + + log.debug("Set OnlineApplicationURL to " + serviceURL); + spEntityDescriptor.setEntityID(serviceURL); + + SPSSODescriptor spSSODescriptor = SAML2Utils + .createSAMLObject(SPSSODescriptor.class); + + spSSODescriptor.setAuthnRequestsSigned(true); + spSSODescriptor.setWantAssertionsSigned(true); + + X509KeyInfoGeneratorFactory keyInfoFactory = new X509KeyInfoGeneratorFactory(); + keyInfoFactory.setEmitEntityCertificate(true); + KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); + + KeyStore keyStore = config.getPVP2KeyStore(); + + X509Credential signingcredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreMetadataKeyAlias(), + config.getPVP2KeystoreMetadataKeyPassword().toCharArray()); + + + log.debug("Set Metadata key information"); + //Set MetaData Signing key + KeyDescriptor entitiesSignKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + entitiesSignKeyDescriptor.setUse(UsageType.SIGNING); + entitiesSignKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(signingcredential)); + Signature entitiesSignature = getSignature(signingcredential); + spEntitiesDescriptor.setSignature(entitiesSignature); + + //Set AuthRequest Signing certificate + X509Credential authcredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreAuthRequestKeyAlias(), + config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); + KeyDescriptor signKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + signKeyDescriptor.setUse(UsageType.SIGNING); + signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential)); + spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); + + + //set AuthRequest encryption certificate + if (MiscUtil.isNotEmpty(config.getPVP2KeystoreAuthRequestEncryptionKeyAlias())) { + X509Credential authEncCredential = new KeyStoreX509CredentialAdapter( + keyStore, + config.getPVP2KeystoreAuthRequestEncryptionKeyAlias(), + config.getPVP2KeystoreAuthRequestEncryptionKeyPassword().toCharArray()); + KeyDescriptor encryKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + encryKeyDescriptor.setUse(UsageType.ENCRYPTION); + encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential)); + spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor); + + } else { + log.warn("No Assertion Encryption-Key defined. This setting is not recommended!"); + + } + + + NameIDFormat persistentnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); + persistentnameIDFormat.setFormat(NameIDType.PERSISTENT); + + spSSODescriptor.getNameIDFormats().add(persistentnameIDFormat); + + NameIDFormat transientnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); + transientnameIDFormat.setFormat(NameIDType.TRANSIENT); + + spSSODescriptor.getNameIDFormats().add(transientnameIDFormat); + + NameIDFormat unspecifiednameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); + unspecifiednameIDFormat.setFormat(NameIDType.UNSPECIFIED); + + spSSODescriptor.getNameIDFormats().add(unspecifiednameIDFormat); + + AssertionConsumerService postassertionConsumerService = + SAML2Utils.createSAMLObject(AssertionConsumerService.class); + + postassertionConsumerService.setIndex(0); + postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION); + + spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); + + + //add SLO services + SingleLogoutService postBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + postBindingService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + postBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_FRONT); + spSSODescriptor.getSingleLogoutServices().add(postBindingService); + + SingleLogoutService redirectBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectBindingService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + redirectBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_FRONT); + spSSODescriptor.getSingleLogoutServices().add(redirectBindingService); + + SingleLogoutService soapBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + soapBindingService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); + soapBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_BACK); + spSSODescriptor.getSingleLogoutServices().add(soapBindingService); + + spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); + + spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor); + + spSSODescriptor.setWantAssertionsSigned(true); + spSSODescriptor.setAuthnRequestsSigned(true); + + AttributeConsumingService attributeService = + SAML2Utils.createSAMLObject(AttributeConsumingService.class); + + attributeService.setIndex(0); + attributeService.setIsDefault(true); + ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class); + serviceName.setName(new LocalizedString("Default Service", "de")); + attributeService.getNames().add(serviceName); + + attributeService.getRequestAttributes().addAll(AttributeListBuilder.getRequestedAttributes()); + + spSSODescriptor.getAttributeConsumingServices().add(attributeService); + + DocumentBuilder builder; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory().getMarshaller(spEntitiesDescriptor); + out.marshall(spEntitiesDescriptor, document); + + Signer.signObject(entitiesSignature); + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + StringWriter sw = new StringWriter(); + StreamResult sr = new StreamResult(sw); + DOMSource source = new DOMSource(document); + transformer.transform(source, sr); + sw.close(); + + String metadataXML = sw.toString(); + + response.setContentType("text/xml"); + response.getOutputStream().write(metadataXML.getBytes()); + + response.getOutputStream().close(); + + } catch (ConfigurationException e) { + log.warn("Configuration can not be loaded.", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (NoSuchAlgorithmException e) { + log.warn("Requested Algorithm could not found.", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (KeyStoreException e) { + log.warn("Requested KeyStoreType is not implemented.", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (CertificateException e) { + log.warn("KeyStore can not be opend or userd.", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (SecurityException e) { + log.warn("KeyStore can not be opend or used", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (ParserConfigurationException e) { + log.warn("PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (MarshallingException e) { + log.warn("PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (SignatureException e) { + log.warn("PVP2 Metadata can not be signed", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (TransformerConfigurationException e) { + log.warn("PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (TransformerFactoryConfigurationError e) { + log.warn("PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + + } catch (TransformerException e) { + log.warn("PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + } + + catch (Exception e) { + log.warn("Unspecific PVP2 Metadata createn error", e); + throw new ServletException("MetaData can not be created. Look into LogFiles for more details."); + } + + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java new file mode 100644 index 000000000..4b23089c4 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java @@ -0,0 +1,159 @@ +/* + * 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.configuration.auth.pvp2.servlets; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.saml2.binding.encoding.HTTPSOAP11Encoder; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.LogoutResponse; +import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.ws.soap.soap11.Envelope; +import org.opensaml.ws.soap.soap11.decoder.http.HTTPSOAP11Decoder; +import org.opensaml.ws.transport.http.HttpServletRequestAdapter; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; + +/** + * @author tlenz + * + */ +public class SLOBackChannelServlet extends SLOBasicServlet { + + private static final long serialVersionUID = 1481623547633064922L; + private static final Logger log = LoggerFactory + .getLogger(SLOBackChannelServlet.class); + + /** + * @throws ConfigurationException + */ + public SLOBackChannelServlet() throws ConfigurationException { + super(); + } + + + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + try { + HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool()); + BasicSAMLMessageContext messageContext = + new BasicSAMLMessageContext(); + messageContext + .setInboundMessageTransport(new HttpServletRequestAdapter( + request)); + + soapDecoder.decode(messageContext); + + Envelope inboundMessage = (Envelope) messageContext + .getInboundMessage(); + + if (inboundMessage.getBody() != null) { + List xmlElemList = inboundMessage.getBody().getUnknownXMLObjects(); + + LogoutResponse sloResp; + if (!xmlElemList.isEmpty() && xmlElemList.get(0) instanceof LogoutRequest) { + LogoutRequest sloReq = (LogoutRequest) xmlElemList.get(0); + sloResp = processLogOutRequest(sloReq, request); + + KeyStore keyStore = getConfig().getPVP2KeyStore(); + X509Credential authcredential = new KeyStoreX509CredentialAdapter( + keyStore, + getConfig().getPVP2KeystoreAuthRequestKeyAlias(), + getConfig().getPVP2KeystoreAuthRequestKeyPassword().toCharArray()); + + HTTPSOAP11Encoder encoder = new HTTPSOAP11Encoder(); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + response, true); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + context.setOutboundSAMLMessageSigningCredential(authcredential); + context.setOutboundSAMLMessage(sloResp); + context.setOutboundMessageTransport(responseAdapter); + + encoder.encode(context); + + } else { + log.warn("Received request ist not of type LogOutRequest"); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + + } + } + + } catch (MessageDecodingException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (SecurityException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (NoSuchAlgorithmException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (CertificateException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (KeyStoreException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (ConfigurationException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } catch (MessageEncodingException e) { + log.error("SLO message processing FAILED." , e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + + } + } + + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java new file mode 100644 index 000000000..69adcc661 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java @@ -0,0 +1,271 @@ +/* + * 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.configuration.auth.pvp2.servlets; + +import java.security.NoSuchAlgorithmException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.joda.time.DateTime; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.LogoutResponse; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.id.configuration.Constants; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager; +import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; +import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception; +import at.gv.egovernment.moa.id.configuration.exception.SLOException; +import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper; +import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class SLOBasicServlet extends HttpServlet { + private static final long serialVersionUID = -4547240664871845098L; + private static final Logger log = LoggerFactory + .getLogger(SLOBasicServlet.class); + + private ConfigurationProvider config; + + public SLOBasicServlet() throws ConfigurationException { + config = ConfigurationProvider.getInstance(); + config.initializePVP2Login(); + } + + protected LogoutRequest createLogOutRequest(String nameID, String nameIDFormat, HttpServletRequest request) throws SLOException { + try { + LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + sloReq.setID(gen.generateIdentifier()); + request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, sloReq.getID()); + sloReq.setIssueInstant(new DateTime()); + NameID name = SAML2Utils.createSAMLObject(NameID.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + name.setValue(serviceURL); + issuer.setValue(serviceURL); + issuer.setFormat(NameIDType.ENTITY); + sloReq.setIssuer(issuer); + + NameID userNameID = SAML2Utils.createSAMLObject(NameID.class); + sloReq.setNameID(userNameID); + userNameID.setFormat(nameIDFormat); + userNameID.setValue(nameID); + + return sloReq; + + } catch (NoSuchAlgorithmException e) { + log.warn("Single LogOut request createn FAILED. ", e); + throw new SLOException(); + + } + + } + + protected LogoutResponse processLogOutRequest(LogoutRequest sloReq, HttpServletRequest request) throws NoSuchAlgorithmException { + //check response destination + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + + String responseDestination = sloReq.getDestination(); + if (MiscUtil.isEmpty(responseDestination) || + !responseDestination.startsWith(serviceURL)) { + log.warn("PVPResponse destination does not match requested destination"); + return createSLOResponse(sloReq, StatusCode.REQUESTER_URI, request); + } + + AuthenticationManager authManager = AuthenticationManager.getInstance(); + if (authManager.isActiveUser(sloReq.getNameID().getValue())) { + AuthenticatedUser authUser = authManager.getActiveUser(sloReq.getNameID().getValue()); + log.info("User " + authUser.getGivenName() + " " + authUser.getFamilyName() + " with nameID:" + + authUser.getNameID() + " get logged out by Single LogOut request."); + authManager.removeActiveUser(authUser); + HttpSession session = request.getSession(false); + if (session != null) + session.invalidate(); + + return createSLOResponse(sloReq, StatusCode.SUCCESS_URI, request); + + } else { + log.debug("Single LogOut not possible! User with nameID:" + sloReq.getNameID().getValue() + " is not found."); + return createSLOResponse(sloReq, StatusCode.PARTIAL_LOGOUT_URI, request); + + } + + } + + private LogoutResponse createSLOResponse(LogoutRequest sloReq, String statusCodeURI, HttpServletRequest request) throws NoSuchAlgorithmException { + LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + sloResp.setID(gen.generateIdentifier()); + sloResp.setInResponseTo(sloReq.getID()); + sloResp.setIssueInstant(new DateTime()); + NameID name = SAML2Utils.createSAMLObject(NameID.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + name.setValue(serviceURL); + issuer.setValue(serviceURL); + issuer.setFormat(NameIDType.ENTITY); + sloResp.setIssuer(issuer); + + Status status = SAML2Utils.createSAMLObject(Status.class); + sloResp.setStatus(status); + StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); + statusCode.setValue(statusCodeURI); + status.setStatusCode(statusCode ); + + return sloResp; + } + + protected void validateLogOutResponse(LogoutResponse sloResp, String reqID, HttpServletRequest request, HttpServletResponse response) throws PVP2Exception { + //ckeck InResponseTo matchs requestID + if (MiscUtil.isEmpty(reqID)) { + log.info("NO Sigle LogOut request ID"); + throw new PVP2Exception("NO Sigle LogOut request ID"); + } + + if (!reqID.equals(sloResp.getInResponseTo())) { + log.warn("SLORequestID does not match SLO Response ID!"); + throw new PVP2Exception("SLORequestID does not match SLO Response ID!"); + + } + + //check response destination + String serviceURL = config.getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + + String responseDestination = sloResp.getDestination(); + if (MiscUtil.isEmpty(responseDestination) || + !responseDestination.startsWith(serviceURL)) { + log.warn("PVPResponse destination does not match requested destination"); + throw new PVP2Exception("SLO response destination does not match requested destination"); + } + + request.getSession().invalidate(); + + if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.PARTIAL_LOGOUT_URI)) { + log.warn("Single LogOut process is not completed."); + request.getSession().setAttribute(Constants.SESSION_SLOERROR, + LanguageHelper.getErrorString("webpages.slo.error", request)); + + + } else if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + log.info("Single LogOut process complete."); + request.getSession().setAttribute(Constants.SESSION_SLOSUCCESS, + LanguageHelper.getErrorString("webpages.slo.success", request)); + + + } else { + log.warn("Single LogOut response sends an unsupported statustype " + sloResp.getStatus().getStatusCode().getValue()); + request.getSession().setAttribute(Constants.SESSION_SLOERROR, + LanguageHelper.getErrorString("webpages.slo.error", request)); + + } + String redirectURL = serviceURL + Constants.SERVLET_LOGOUT; + redirectURL = response.encodeRedirectURL(redirectURL); + response.setContentType("text/html"); + response.setStatus(302); + response.addHeader("Location", redirectURL); + + } + + protected SingleLogoutService findIDPFrontChannelSLOService() throws + ConfigurationException, SLOException { + + String entityname = config.getPVP2IDPMetadataEntityName(); + if (MiscUtil.isEmpty(entityname)) { + log.info("No IDP EntityName configurated"); + throw new ConfigurationException("No IDP EntityName configurated"); + } + + //get IDP metadata from metadataprovider + HTTPMetadataProvider idpmetadata = config.getMetaDataProvier(); + try { + EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname); + if (idpEntity == null) { + log.info("IDP EntityName is not found in IDP Metadata"); + throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); + + } + + //select authentication-service url from metadata + SingleLogoutService redirectEndpoint = null; + for (SingleLogoutService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) { + + //Get the service address for the binding you wish to use + if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) + redirectEndpoint = sss; + + else if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) && + redirectEndpoint == null) + redirectEndpoint = sss; + } + + if (redirectEndpoint == null) { + log.warn("Single LogOut FAILED: IDP implements no frontchannel SLO service."); + throw new SLOException("Single LogOut FAILED: IDP implements no frontchannel SLO service."); + } + + return redirectEndpoint; + } catch (MetadataProviderException e) { + log.info("IDP EntityName is not found in IDP Metadata", e); + throw new ConfigurationException("IDP EntityName is not found in IDP Metadata"); + + } + } + + protected ConfigurationProvider getConfig() { + return config; + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java new file mode 100644 index 000000000..eb5752982 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java @@ -0,0 +1,287 @@ +/* + * 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.configuration.auth.pvp2.servlets; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opensaml.common.SAMLObject; +import org.opensaml.common.SignableSAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; +import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder; +import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule; +import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.LogoutResponse; +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.ws.security.SecurityPolicyException; +import org.opensaml.ws.security.SecurityPolicyResolver; +import org.opensaml.ws.security.provider.BasicSecurityPolicy; +import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver; +import org.opensaml.ws.transport.http.HttpServletRequestAdapter; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.AbstractSignableXMLObject; +import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.xml.validation.ValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.id.configuration.Constants; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager; +import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils; +import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; +import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception; +import at.gv.egovernment.moa.id.configuration.exception.SLOException; +import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class SLOFrontChannelServlet extends SLOBasicServlet { + + private static final long serialVersionUID = -6280199681356977759L; + private static final Logger log = LoggerFactory + .getLogger(SLOFrontChannelServlet.class); + + /** + * @throws ConfigurationException + */ + public SLOFrontChannelServlet() throws ConfigurationException { + super(); + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + try { + if (MiscUtil.isNotEmpty(request.getParameter(Constants.REQUEST_USERSLO))) { + //process user initiated single logout process + Object authUserObj = request.getSession().getAttribute(Constants.SESSION_AUTH); + AuthenticatedUser authUser = (AuthenticatedUser) authUserObj; + + String nameIDFormat = authUser.getNameIDFormat(); + String nameID = authUser.getNameID(); + + //remove user + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.removeActiveUser(authUser); + + if (MiscUtil.isEmpty(nameID) || MiscUtil.isEmpty(nameIDFormat)) { + log.warn("No user information found. Single Log-Out not possible"); + buildErrorMessage(request, response); + + } else + log.info("Fount user information for user nameID: " + nameID + + " , nameIDFormat: " + nameIDFormat + + ". Build Single Log-Out request ..."); + + //build SLO request to IDP + LogoutRequest sloReq = createLogOutRequest(nameID, nameIDFormat, request); + + //send message + sendMessage(request, response, sloReq, null); + + } else { + //process PVP 2.1 single logout process + HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( + new BasicParserPool()); + BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); + messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request)); + messageContext.setMetadataProvider(getConfig().getMetaDataProvier()); + + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule(); + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + policy.getPolicyRules().add(signedRole); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setSecurityPolicyResolver(resolver); + messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + + signatureRule.evaluate(messageContext); + decode.decode(messageContext); + + processMessage(request, response, + messageContext.getInboundMessage(), messageContext.getRelayState()); + + } + + } catch (SLOException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (ConfigurationException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (PVP2Exception e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (SecurityPolicyException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (MessageDecodingException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (SecurityException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (NoSuchAlgorithmException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + try { + HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); + BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); + messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request)); + decode.decode(messageContext); + + PVP2Utils.validateSignature((SignableXMLObject) messageContext.getInboundMessage(), getConfig()); + + processMessage(request, response, + messageContext.getInboundMessage(), messageContext.getRelayState()); + + + } catch (MessageDecodingException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (SecurityException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (ValidationException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (ConfigurationException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (PVP2Exception e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } catch (NoSuchAlgorithmException e) { + log.error("Single LogOut processing error.", e); + buildErrorMessage(request, response); + + } + } + + private void buildErrorMessage(HttpServletRequest request, HttpServletResponse response) { + + request.getSession().setAttribute(Constants.SESSION_SLOERROR, + LanguageHelper.getErrorString("webpages.slo.error", request)); + + //check response destination + String serviceURL = getConfig().getPublicUrlPreFix(request); + if (!serviceURL.endsWith("/")) + serviceURL = serviceURL + "/"; + + String redirectURL = serviceURL + Constants.SERVLET_LOGOUT; + redirectURL = response.encodeRedirectURL(redirectURL); + response.setContentType("text/html"); + response.setStatus(302); + response.addHeader("Location", redirectURL); + } + + private void processMessage(HttpServletRequest request, HttpServletResponse response, + XMLObject xmlObject, String relayState) throws ConfigurationException, PVP2Exception, NoSuchAlgorithmException { + if (xmlObject instanceof LogoutRequest) { + LogoutResponse sloResp = + processLogOutRequest((LogoutRequest) xmlObject, request); + sendMessage(request, response, sloResp, relayState); + + } else if (xmlObject instanceof LogoutResponse) { + LogoutResponse sloResp = (LogoutResponse) xmlObject; + + String reqID = (String) request.getSession().getAttribute(Constants.SESSION_PVP2REQUESTID); + request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, null); + validateLogOutResponse(sloResp, reqID, request, response); + + } + } + + private void sendMessage(HttpServletRequest request, HttpServletResponse response, + RequestAbstractType sloReq, String relayState) throws ConfigurationException, PVP2Exception { + SingleLogoutService sloService = findIDPFrontChannelSLOService(); + sloReq.setDestination(sloService.getLocation()); + sendMessage(request, response, sloReq, sloService, relayState); + } + + private void sendMessage(HttpServletRequest request, HttpServletResponse response, + StatusResponseType sloReq, String relayState) throws ConfigurationException, PVP2Exception { + SingleLogoutService sloService = findIDPFrontChannelSLOService(); + sloReq.setDestination(sloService.getLocation()); + sendMessage(request, response, sloReq, sloService, relayState); + } + + private void sendMessage(HttpServletRequest request, HttpServletResponse response, + SignableSAMLObject sloReq, SingleLogoutService sloService, String relayState) throws ConfigurationException, PVP2Exception { + X509Credential authcredential = PVP2Utils.signMessage((AbstractSignableXMLObject) sloReq, getConfig()); + if (sloService.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) + PVP2Utils.postBindingEncoder(request, response, sloReq, authcredential, sloService.getLocation(), relayState); + + else if (sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) + PVP2Utils.redirectBindingEncoder(request, response, sloReq, authcredential, sloService.getLocation(), relayState); + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java index a2aa2a8a4..e176e5141 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java @@ -53,12 +53,10 @@ import at.gv.egovernment.moa.id.commons.db.dao.config.ChainingModeType; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.configuration.Constants; import at.gv.egovernment.moa.id.configuration.auth.pvp2.MetaDataVerificationFilter; import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; import at.gv.egovernment.moa.id.configuration.utils.UserRequestCleaner; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; @@ -85,8 +83,12 @@ public class ConfigurationProvider { private boolean pvp2logininitialzied = false; public static ConfigurationProvider getInstance() throws ConfigurationException { + if (instance == null) { - instance = new ConfigurationProvider(); + synchronized (ConfigurationProvider.class) { + instance = new ConfigurationProvider(); + } + } return instance; diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java new file mode 100644 index 000000000..c941c4bbe --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java @@ -0,0 +1,55 @@ +/* + * 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.configuration.exception; + +/** + * @author tlenz + * + */ +public class PVP2Exception extends Exception { + + private static final long serialVersionUID = -3887330440491843927L; + + /** + * @param string + */ + public PVP2Exception(String string) { + super(string); + } + + /** + * + */ + public PVP2Exception() { + super(); + } + + /** + * @param string + * @param e + */ + public PVP2Exception(String string, Throwable e) { + super(string, e); + } + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java new file mode 100644 index 000000000..5d34397f4 --- /dev/null +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java @@ -0,0 +1,53 @@ +/* + * 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.configuration.exception; + +import java.security.NoSuchAlgorithmException; + +/** + * @author tlenz + * + */ +public class SLOException extends PVP2Exception { + /** + * @param string + */ + public SLOException(String string) { + super(string); + } + + public SLOException() { + super(); + } + + /** + * @param string + * @param e + */ + public SLOException(String string, Throwable e) { + super(string, e); + } + + private static final long serialVersionUID = 6443077827626969931L; + +} diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java index 190773bf0..9ca1d08cc 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java @@ -43,6 +43,7 @@ import javax.servlet.http.HttpSession; import at.gv.egovernment.moa.id.configuration.Constants; import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager; import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; import at.gv.egovernment.moa.util.MiscUtil; @@ -136,12 +137,26 @@ public class AuthenticationFilter implements Filter{ HttpSession session = httpServletRequest.getSession(); - Object authuser = session.getAttribute(Constants.SESSION_AUTH); + Object authuserobj = session.getAttribute(Constants.SESSION_AUTH); + AuthenticatedUser authuser = (AuthenticatedUser) authuserobj; String requestURL = WebAppUtil.getRequestURLWithParameters(httpServletRequest, true); log.trace("Request URL: " + requestURL); + AuthenticationManager authManager = AuthenticationManager.getInstance(); + if (!authManager.isActiveUser(authuser)) { + //user is not active anymore. Invalidate session and reauthenticate user + String authID = (String) session.getAttribute(Constants.SESSION_PVP2REQUESTID); + session.invalidate(); + authuser = null; + + //TODO: set infotext + + session = httpServletRequest.getSession(true); + session.setAttribute(Constants.SESSION_PVP2REQUESTID, authID); + } + if (authuser == null && !this.isExcluded(requestURL)) { if (config.isLoginDeaktivated()) { @@ -151,6 +166,8 @@ public class AuthenticationFilter implements Filter{ if (authuser == null) { authuser = AuthenticatedUser.generateDefaultUser(); + authManager.setActiveUser(authuser); + //authuser = new AuthenticatedUser(1, "Max", "TestUser", true, false); httpServletRequest.getSession().setAttribute(Constants.SESSION_AUTH, authuser); } @@ -188,23 +205,23 @@ public class AuthenticationFilter implements Filter{ return; } - } - } - try { - filterchain.doFilter(req, resp); - } catch (Exception e) { + } else { + try { + filterchain.doFilter(req, resp); + + } catch (Exception e) { -// String redirectURL = "./index.action"; -// HttpServletResponse httpResp = (HttpServletResponse) resp; -// redirectURL = httpResp.encodeRedirectURL(redirectURL); -// resp.setContentType("text/html"); -// ((HttpServletResponse) resp).setStatus(302); -// httpResp.addHeader("Location", redirectURL); -// log.warn("A Filter Error occurs -> Redirect to Login-Form"); - } - + //String redirectURL = "./index.action"; + //HttpServletResponse httpResp = (HttpServletResponse) resp; + //redirectURL = httpResp.encodeRedirectURL(redirectURL); + //resp.setContentType("text/html"); + //((HttpServletResponse) resp).setStatus(302); + //httpResp.addHeader("Location", redirectURL); + //log.warn("A Filter Error occurs -> Redirect to Login-Form"); + } + } } public void init(FilterConfig filterConfig) throws ServletException { diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java index 24ee653f3..cd6c699b9 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java @@ -88,7 +88,7 @@ public class FormDataHelper { userlist.add(new AuthenticatedUser(dbuser, dbuser.isIsActive(), ismandate, - false)); + false, null, null)); } return userlist; } diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java index e019b70bb..980bb1e59 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java @@ -85,6 +85,8 @@ import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.commons.validation.ValidationHelper; import at.gv.egovernment.moa.id.configuration.Constants; import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser; +import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager; +import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils; import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; import at.gv.egovernment.moa.id.configuration.data.UserDatabaseFrom; import at.gv.egovernment.moa.id.configuration.exception.BasicActionException; @@ -216,8 +218,14 @@ public class IndexAction extends BasicAction { AuthenticatedUser authuser = new AuthenticatedUser(dbuser, true, ismandateuser, - false); + false, + dbuser.getHjid()+"dbID", + "username/password"); + //store user as authenticated user + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.setActiveUser(authUser); + Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin()); if (date != null) authuser.setLastLogin(date);; @@ -308,31 +316,10 @@ public class IndexAction extends BasicAction { addActionError(LanguageHelper.getErrorString("error.login", request)); return Constants.STRUTS_ERROR; } - - //Validate Signature - SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); - profileValidator.validate(sign); - - //Verify Signature - List keyInfoProvider = new ArrayList(); - keyInfoProvider.add(new DSAKeyValueProvider()); - keyInfoProvider.add(new RSAKeyValueProvider()); - keyInfoProvider.add(new InlineX509DataProvider()); - KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( - keyInfoProvider); - - MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); - MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier()); - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new EntityIDCriteria(configuration.getPVP2IDPMetadataEntityName())); - criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); - - ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); - trustEngine.validate(sign, criteriaSet); - + //validate signature + PVP2Utils.validateSignature(samlResponse, configuration); + log.info("PVP2 Assertion is valid"); if (samlResponse.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { @@ -444,7 +431,14 @@ public class IndexAction extends BasicAction { } } - authUser = AuthenticatedUser.generateUserRequestUser(user); + //create AuthUser data element + authUser = AuthenticatedUser.generateUserRequestUser(user, + nameID.getValue(), + nameID.getFormat()); + + //store user as authenticated user + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.setActiveUser(authUser); //set Random value formID = Random.nextRandom(); @@ -468,7 +462,14 @@ public class IndexAction extends BasicAction { authUser = new AuthenticatedUser(dbuser, false, dbuser.isIsMandateUser(), - true); + true, + nameID.getValue(), + nameID.getFormat()); + + //store user as authenticated user + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.setActiveUser(authUser); + session.setAttribute(Constants.SESSION_FORM, user); session.setAttribute(Constants.SESSION_AUTH, authUser); @@ -488,7 +489,13 @@ public class IndexAction extends BasicAction { authUser = new AuthenticatedUser(dbuser, true, ismandateuser, - true); + true, + nameID.getValue(), + nameID.getFormat()); + + //store user as authenticated user + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.setActiveUser(authUser); Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin()); if (date != null) @@ -507,7 +514,7 @@ public class IndexAction extends BasicAction { finally { ConfigurationDBUtils.closeSession(); } - + HttpSession newsession = generateNewJSession(request); newsession.setAttribute(Constants.SESSION_AUTH, authUser); return Constants.STRUTS_SUCCESS; @@ -785,33 +792,19 @@ public class IndexAction extends BasicAction { } public String logout() { - - try { - populateBasicInformations(); + HttpSession session = request.getSession(false); + + if (session != null) { + if (MiscUtil.isNotEmpty((String)session.getAttribute(Constants.SESSION_SLOSUCCESS))) + addActionMessage((String)session.getAttribute(Constants.SESSION_SLOSUCCESS)); - } catch (BasicActionException e) { - return Constants.STRUTS_ERROR; + if (MiscUtil.isNotEmpty((String)session.getAttribute(Constants.SESSION_SLOERROR))) + addActionError((String)session.getAttribute(Constants.SESSION_SLOERROR)); - } - - if (session != null) session.invalidate(); - - try { - ConfigurationProvider config = ConfigurationProvider.getInstance(); - String ssologout = config.getSSOLogOutURL(); - if (MiscUtil.isNotEmpty(ssologout) && authUser != null && authUser.isPVP2Login()) { - ssologouturl = ssologout + config.getPublicUrlPreFix(request) + "/index.action"; - return Constants.STRUTS_SSOLOGOUT; + } - } - - } catch (ConfigurationException e) { - log.warn("Configuration can not be loaded.", e); - - } - return Constants.STRUTS_SUCCESS; } diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties index 1f0819edf..f379a7a34 100644 --- a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties +++ b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties @@ -35,8 +35,11 @@ error.oa.oauth.clientSecret=Client-Secret darf nicht leer sein error.oa.oauth.keyname=Key-Name darf nicht leer sein error.oa.oauth.keystore=Keystore darf nicht leer sein und muss eine richtige URL sein. + mail.userrequest.subject=Accountanforderung MOA-ID 2.x Konfigurationstool +webpages.slo.error=Der Abmeldevorgang bei allen Online-Applikationen war nicht erfolgreich. Bitte schlie \u00dfen Sie aus Sicherheitsgr\u00FCnden ihren Browser. +webpages.slo.success=Sie wurden erfolgreich bei allen Online-Applikationen abgemeldet. webpages.error.header=Es ist ein Fehler aufgetreten webpages.index.header=Willkommen bei der MOA-ID 2.x Konfigurationsapplikation diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties index 7733be5d0..398df94a5 100644 --- a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties +++ b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties @@ -38,6 +38,9 @@ error.oa.oauth.keystore=Keystore cannot be blank and has to be provided in the f mail.userrequest.subject=Requesting accounts - MOA-ID 2.x Config Tool +webpages.slo.error=LogOut process finished with an error. For security reasons, please close your browser. +webpages.slo.success=LogOut process finished successful + webpages.error.header=The error occured webpages.index.header=Welcome to MOA-ID 2.x Configuration webpages.index.desciption.head=In order to use this service you should log in diff --git a/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml b/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml index 3919d3ff3..a6fe50269 100644 --- a/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml +++ b/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml @@ -64,15 +64,27 @@ pvp2login pvp2login - at.gv.egovernment.moa.id.configuration.auth.pvp2.Authenticate + at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.Authenticate buildmetadata buildmetadata - at.gv.egovernment.moa.id.configuration.auth.pvp2.BuildMetadata + at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.BuildMetadata + + slofrontchannel + Single LogOut FrontChannel Service + at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOFrontChannelServlet + + + + slobackchannel + Single LogOut BackChannel Service + at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOBackChannelServlet + + buildmetadata /servlet/metadata @@ -83,6 +95,16 @@ /servlet/pvp2login + + slofrontchannel + /servlet/sloFrontChannel + + + + slobackchannel + /servlet/sloBackChannel + + + + + axis axis diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml index 770182a4f..1f392f7ec 100644 --- a/id/server/idserverlib/pom.xml +++ b/id/server/idserverlib/pom.xml @@ -246,7 +246,11 @@ commons-lang 2.6 - + + eu.stork + DocumentService + 0.0.1-SNAPSHOT + diff --git a/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT-classes.jar b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT-classes.jar new file mode 100644 index 000000000..d338cb3d6 Binary files /dev/null and b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT-classes.jar differ diff --git a/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.jar b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.jar new file mode 100644 index 000000000..411ba64b7 Binary files /dev/null and b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.jar differ diff --git a/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.pom b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.pom new file mode 100644 index 000000000..519d70468 --- /dev/null +++ b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.pom @@ -0,0 +1,154 @@ + + 4.0.0 + eu.stork + DocumentService + 0.0.1-SNAPSHOT + DocumentService + DTL webservice + + + + log4j + log4j + 1.2.17 + + + javax.jms + jms + + + com.sun.jdmk + jmxtools + + + com.sun.jmx + jmxri + + + mail + javax.mail + + + + + + + junit + junit + 4.1 + + + mysql + mysql-connector-java + 5.1.27 + + + org.glassfish.jersey.core + jersey-common + 2.0-m03 + + + + org.apache.axis + axis + 1.4 + + + + + + + + com.sun.xml.ws + jaxws-tools + 2.2.8 + + + com.sun.xml.ws + jaxws-rt + 2.2.8 + provided + + + javax.xml + jaxrpc-api + 1.1 + + + + org.bouncycastle + bcprov-jdk16 + 1.46 + + + com.sun.xml.security + xml-security-impl + 1.0 + + + org.jvnet + mimepull + 1.6 + + + eu.stork + SamlEngine + 1.4.0 + + + + + + + + + + + DocumentService + src + + + src + + **/*.java + + + + + + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + maven-war-plugin + 2.3 + + WebContent + false + true + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + + + + + + jar + + + + + + + jar + diff --git a/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.war b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.war new file mode 100644 index 000000000..b6622a63c Binary files /dev/null and b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/DocumentService-0.0.1-SNAPSHOT.war differ diff --git a/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/maven-metadata-local.xml new file mode 100644 index 000000000..be8b41c9d --- /dev/null +++ b/repository/eu/stork/DocumentService/0.0.1-SNAPSHOT/maven-metadata-local.xml @@ -0,0 +1,35 @@ + + + eu.stork + DocumentService + 0.0.1-SNAPSHOT + + + true + + 20140605160207 + + + jar + 0.0.1-SNAPSHOT + 20140605160207 + + + pom + 0.0.1-SNAPSHOT + 20140605160207 + + + classes + jar + 0.0.1-SNAPSHOT + 20140605160137 + + + war + 0.0.1-SNAPSHOT + 20140605160137 + + + + diff --git a/repository/eu/stork/DocumentService/maven-metadata-local.xml b/repository/eu/stork/DocumentService/maven-metadata-local.xml new file mode 100644 index 000000000..325a76ecd --- /dev/null +++ b/repository/eu/stork/DocumentService/maven-metadata-local.xml @@ -0,0 +1,11 @@ + + + eu.stork + DocumentService + + + 0.0.1-SNAPSHOT + + 20140604172305 + + -- cgit v1.2.3 From c8a872dcffe918d9ed1e867cb9fc18f639a715b4 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Jun 2014 07:06:20 +0200 Subject: only use redirectBinding for inbound SLO --- .../moa/id/protocols/pvp2x/MetadataAction.java | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java index c60e69df6..1085e4cbc 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java @@ -253,18 +253,18 @@ public class MetadataAction implements IAction { redirectassertionConsumerService.setIndex(1); redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); redirectassertionConsumerService.setLocation(PVPConfiguration - .getInstance().getIDPSSORedirectService()); + .getInstance().getIDPSSORedirectService()); spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService); //add SLO descriptor - SingleLogoutService postSLOService = - SAML2Utils.createSAMLObject(SingleLogoutService.class); - postSLOService.setLocation(PVPConfiguration - .getInstance().getIDPSSOPostService()); - postSLOService - .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - spSSODescriptor.getSingleLogoutServices().add(postSLOService); +// SingleLogoutService postSLOService = +// SAML2Utils.createSAMLObject(SingleLogoutService.class); +// postSLOService.setLocation(PVPConfiguration +// .getInstance().getIDPSSOPostService()); +// postSLOService +// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); +// spSSODescriptor.getSingleLogoutServices().add(postSLOService); SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); @@ -333,13 +333,13 @@ public class MetadataAction implements IAction { postSingleSignOnService); //add SLO descriptor - SingleLogoutService postSLOService = - SAML2Utils.createSAMLObject(SingleLogoutService.class); - postSLOService.setLocation(PVPConfiguration - .getInstance().getIDPSSOPostService()); - postSLOService - .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - idpSSODescriptor.getSingleLogoutServices().add(postSLOService); +// SingleLogoutService postSLOService = +// SAML2Utils.createSAMLObject(SingleLogoutService.class); +// postSLOService.setLocation(PVPConfiguration +// .getInstance().getIDPSSOPostService()); +// postSLOService +// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); +// idpSSODescriptor.getSingleLogoutServices().add(postSLOService); } -- cgit v1.2.3 From 5677982c24ada5c0a56e11588b5839bc2a75b83e Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Jun 2014 13:47:15 +0200 Subject: use different endpoints for IDP and interfederation SP --- .../moa/id/protocols/pvp2x/MetadataAction.java | 6 +-- .../moa/id/protocols/pvp2x/PVP2XProtocol.java | 59 ++++++++++++++++------ .../protocols/pvp2x/binding/ArtifactBinding.java | 2 +- .../moa/id/protocols/pvp2x/binding/IDecoder.java | 2 +- .../id/protocols/pvp2x/binding/PostBinding.java | 33 ++++++------ .../protocols/pvp2x/binding/RedirectBinding.java | 31 ++++++------ .../id/protocols/pvp2x/binding/SoapBinding.java | 2 +- .../protocols/pvp2x/config/PVPConfiguration.java | 36 ++++++++----- 8 files changed, 103 insertions(+), 68 deletions(-) diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java index 1085e4cbc..fec8e3b98 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java @@ -244,7 +244,7 @@ public class MetadataAction implements IAction { postassertionConsumerService.setIndex(0); postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); postassertionConsumerService.setLocation(PVPConfiguration - .getInstance().getIDPSSOPostService()); + .getInstance().getSPSSOPostService()); postassertionConsumerService.setIsDefault(true); spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); @@ -253,7 +253,7 @@ public class MetadataAction implements IAction { redirectassertionConsumerService.setIndex(1); redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); redirectassertionConsumerService.setLocation(PVPConfiguration - .getInstance().getIDPSSORedirectService()); + .getInstance().getSPSSORedirectService()); spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService); @@ -269,7 +269,7 @@ public class MetadataAction implements IAction { SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); redirectSLOService.setLocation(PVPConfiguration - .getInstance().getIDPSSOPostService()); + .getInstance().getSPSSORedirectService()); redirectSLOService .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java index d9ce6250a..7f8ea91bd 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java @@ -111,6 +111,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { public static final String ATTRIBUTEQUERY = "AttributeQuery"; public static final String SINGLELOGOUT = "SingleLogOut"; + public static final String ENDPOINT_IDP = "idp"; + public static final String ENDPOINT_SP = "sp"; + + public static final String PARAMETER_ENDPOINT = "endpointtype"; + private static List decoder = new ArrayList(); private static HashMap actions = new HashMap(); @@ -168,6 +173,23 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return null; } + private boolean isServiceProviderEndPointUsed(HttpServletRequest req) throws InvalidProtocolRequestException { + Object obj = req.getParameter(PARAMETER_ENDPOINT); + if (obj instanceof String) { + String param = (String) obj; + if (MiscUtil.isNotEmpty(param)) { + if (ENDPOINT_IDP.equals(param)) + return false; + + else if (ENDPOINT_SP.equals(param)) + return true; + } + } + + Logger.error("No valid PVP 2.1 entpoint descriptor"); + throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); + } + public PVP2XProtocol() { super(); } @@ -193,7 +215,8 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return null; } try { - InboundMessage msg = (InboundMessage) decoder.decode(request, response); + + InboundMessage msg = (InboundMessage) decoder.decode(request, response, isServiceProviderEndPointUsed(request)); if (MiscUtil.isEmpty(msg.getEntityID())) { throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); @@ -217,13 +240,14 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { else if (msg instanceof MOARequest && ((MOARequest)msg).getSamlRequest() instanceof LogoutRequest) - return preProcessLogOut(request, response, (MOARequest) msg); + return preProcessLogOut(request, response, msg); - else if (msg instanceof MOARequest && - ((MOARequest)msg).getSamlRequest() instanceof LogoutResponse) - return preProcessLogOut(request, response, (MOARequest) msg); + else if (msg instanceof MOAResponse && + ((MOAResponse)msg).getResponse() instanceof LogoutResponse) + return preProcessLogOut(request, response, msg); - else if (msg instanceof MOAResponse) { + else if (msg instanceof MOAResponse && + ((MOAResponse)msg).getResponse() instanceof Response) { //load service provider AuthRequest from session IRequest obj = RequestStorage.getPendingRequest(msg.getRelayState()); @@ -420,20 +444,22 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { * @throws MOAIDException */ private IRequest preProcessLogOut(HttpServletRequest request, - HttpServletResponse response, MOARequest msg) throws MOAIDException { + HttpServletResponse response, InboundMessage inMsg) throws MOAIDException { PVPTargetConfiguration config = new PVPTargetConfiguration(); - if (((MOARequest)msg).getSamlRequest() instanceof LogoutRequest) { + MOARequest msg; + if (inMsg instanceof MOARequest && + ((MOARequest)inMsg).getSamlRequest() instanceof LogoutRequest) { //preProcess single logout request from service provider - + + msg = (MOARequest) inMsg; + EntityDescriptor metadata = msg.getEntityMetadata(); if(metadata == null) { throw new NoMetadataInformationException(); } - - String oaURL = metadata.getEntityID(); oaURL = StringEscapeUtils.escapeHtml(oaURL); @@ -443,10 +469,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { config.setBinding(msg.getRequestBinding()); - } else if (((MOARequest)msg).getSamlRequest() instanceof LogoutResponse) { + } else if (inMsg instanceof MOAResponse && + ((MOAResponse)inMsg).getResponse() instanceof LogoutResponse) { //preProcess single logour response from service provider - LogoutResponse resp = (LogoutResponse) (((MOARequest)msg).getSamlRequest()); + LogoutResponse resp = (LogoutResponse) (((MOAResponse)inMsg).getResponse()); Logger.debug("PreProcess SLO Response from " + resp.getIssuer()); @@ -458,14 +485,14 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { } //TODO: check if relayState exists - msg.getRelayState(); + inMsg.getRelayState(); } else throw new MOAIDException("Unsupported request", new Object[] {}); - config.setRequest(msg); + config.setRequest(inMsg); config.setAction(SINGLELOGOUT); return config; } @@ -624,7 +651,7 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { */ private MOAResponse preProcessAuthResponse(MOAResponse msg) { Logger.debug("Start PVP21 assertion processing... "); - Response samlResp = msg.getResponse(); + Response samlResp = (Response) msg.getResponse(); try { if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java index 8691667f0..4d353ffcd 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java @@ -102,7 +102,7 @@ public class ArtifactBinding implements IDecoder, IEncoder { } public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp) throws MessageDecodingException, + HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException { return null; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java index fb17c02b8..6619876dc 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java @@ -33,7 +33,7 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface public interface IDecoder { public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp) + HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException, PVP2Exception; public boolean handleDecode(String action, HttpServletRequest req); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java index a2fe5c01b..7f73b1ed7 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java @@ -139,7 +139,7 @@ public class PostBinding implements IDecoder, IEncoder { } public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp) throws MessageDecodingException, + HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException { HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); @@ -152,39 +152,38 @@ public class PostBinding implements IDecoder, IEncoder { } catch (ConfigurationException e) { throw new SecurityException(e); } - - decode.decode(messageContext); - + messageContext.setMetadataProvider(MOAMetadataProvider.getInstance()); - InboundMessage msg = null; + //set metadata descriptor type + if (isSPEndPoint) + messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + else + messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - if (messageContext.getInboundMessage() instanceof RequestAbstractType) { - messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - + decode.decode(messageContext); + + InboundMessage msg = null; + if (messageContext.getInboundMessage() instanceof RequestAbstractType) { RequestAbstractType inboundMessage = (RequestAbstractType) messageContext .getInboundMessage(); msg = new MOARequest(inboundMessage, getSAML2BindingName()); - } else if (messageContext.getInboundMessage() instanceof Response){ - messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - - Response inboundMessage = (Response) messageContext.getInboundMessage(); + } else if (messageContext.getInboundMessage() instanceof StatusResponseType){ + StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage(); msg = new MOAResponse(inboundMessage); } else //create empty container if request type is unknown msg = new InboundMessage(); - - msg.setVerified(false); - - decode.decode(messageContext); + if (messageContext.getPeerEntityMetadata() != null) msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); else Logger.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer()); - + + msg.setVerified(false); msg.setRelayState(messageContext.getRelayState()); return msg; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java index 8fba6cde0..26f6f3a62 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java @@ -129,7 +129,7 @@ public class RedirectBinding implements IDecoder, IEncoder { } public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp) throws MessageDecodingException, + HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException { HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( @@ -146,8 +146,6 @@ public class RedirectBinding implements IDecoder, IEncoder { BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext .setInboundMessageTransport(new HttpServletRequestAdapter(req)); - - decode.decode(messageContext); messageContext.setMetadataProvider(MOAMetadataProvider.getInstance()); @@ -161,36 +159,39 @@ public class RedirectBinding implements IDecoder, IEncoder { policy); messageContext.setSecurityPolicyResolver(resolver); - InboundMessage msg = null; - - if (messageContext.getInboundMessage() instanceof RequestAbstractType) { + //set metadata descriptor type + if (isSPEndPoint) + messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + else messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - + + decode.decode(messageContext); + + //check signature + signatureRule.evaluate(messageContext); + + InboundMessage msg = null; + if (messageContext.getInboundMessage() instanceof RequestAbstractType) { RequestAbstractType inboundMessage = (RequestAbstractType) messageContext .getInboundMessage(); msg = new MOARequest(inboundMessage, getSAML2BindingName()); - } else if (messageContext.getInboundMessage() instanceof Response){ - messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - - Response inboundMessage = (Response) messageContext.getInboundMessage(); + } else if (messageContext.getInboundMessage() instanceof StatusResponseType){ + StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage(); msg = new MOAResponse(inboundMessage); } else //create empty container if request type is unknown msg = new InboundMessage(); - signatureRule.evaluate(messageContext); - msg.setVerified(true); - - decode.decode(messageContext); if (messageContext.getPeerEntityMetadata() != null) msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); else Logger.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer()); + msg.setVerified(true); msg.setRelayState(messageContext.getRelayState()); return msg; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java index 75332cfea..f0eafe272 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java @@ -59,7 +59,7 @@ import at.gv.egovernment.moa.logging.Logger; public class SoapBinding implements IDecoder, IEncoder { public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp) throws MessageDecodingException, + HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException, PVP2Exception { HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool()); BasicSAMLMessageContext messageContext = diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java index 255fba093..d3a9ad3e7 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java @@ -33,7 +33,6 @@ import java.util.Properties; import java.util.jar.Attributes; import java.util.jar.Manifest; -import org.opensaml.Configuration; import org.opensaml.saml2.metadata.Company; import org.opensaml.saml2.metadata.ContactPerson; import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; @@ -46,7 +45,6 @@ import org.opensaml.saml2.metadata.OrganizationName; import org.opensaml.saml2.metadata.OrganizationURL; import org.opensaml.saml2.metadata.SurName; import org.opensaml.saml2.metadata.TelephoneNumber; -import org.opensaml.xml.security.SecurityConfiguration; import at.gv.egovernment.moa.id.commons.db.dao.config.Contact; import at.gv.egovernment.moa.id.commons.db.dao.config.OAPVP2; @@ -71,10 +69,12 @@ public class PVPConfiguration { } public static final String PVP2_METADATA = "/pvp2/metadata"; - public static final String PVP2_REDIRECT = "/pvp2/redirect"; - public static final String PVP2_POST = "/pvp2/post"; - public static final String PVP2_SOAP = "/pvp2/soap"; - public static final String PVP2_ATTRIBUTEQUERY = "/pvp2/attributequery"; + public static final String PVP2_IDP_REDIRECT = "/pvp2/redirect"; + public static final String PVP2_IDP_POST = "/pvp2/post"; + public static final String PVP2_IDP_SOAP = "/pvp2/soap"; + public static final String PVP2_IDP_ATTRIBUTEQUERY = "/pvp2/attributequery"; + public static final String PVP2_SP_REDIRECT = "/pvp2/sp/redirect"; + public static final String PVP2_SP_POST = "/pvp2/sp/post"; public static final String PVP_CONFIG_FILE = "pvp2config.properties"; @@ -143,22 +143,30 @@ public class PVPConfiguration { return publicPath; } - public String getIDPSSOPostService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_POST; + public String getSPSSOPostService() throws ConfigurationException { + return getIDPPublicPath() + PVP2_SP_POST; } - public String getIDPSSOSOAPService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_SOAP; + public String getSPSSORedirectService() throws ConfigurationException { + return getIDPPublicPath() + PVP2_SP_REDIRECT; } - public String getIDPAttributeQueryService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_ATTRIBUTEQUERY; + public String getIDPSSOPostService() throws ConfigurationException { + return getIDPPublicPath() + PVP2_IDP_POST; } - + public String getIDPSSORedirectService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_REDIRECT; + return getIDPPublicPath() + PVP2_IDP_REDIRECT; } + public String getIDPSSOSOAPService() throws ConfigurationException { + return getIDPPublicPath() + PVP2_IDP_SOAP; + } + + public String getIDPAttributeQueryService() throws ConfigurationException { + return getIDPPublicPath() + PVP2_IDP_ATTRIBUTEQUERY; + } + public String getIDPSSOMetadataService() throws ConfigurationException { return getIDPPublicPath() + PVP2_METADATA; } -- cgit v1.2.3 From c1f3b45adb46f2a7a2c93df278d2b8189eb2fc91 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Jun 2014 13:47:48 +0200 Subject: solve some SLO bugs --- .../moa/id/configuration/auth/pvp2/PVP2Utils.java | 36 +++++++++++++--------- .../auth/pvp2/servlets/BuildMetadata.java | 8 ++--- .../auth/pvp2/servlets/SLOBasicServlet.java | 1 - .../auth/pvp2/servlets/SLOFrontChannelServlet.java | 8 +++-- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java index 5032222d0..3d66a4b19 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java @@ -63,6 +63,7 @@ import org.opensaml.xml.security.keyinfo.KeyInfoProvider; import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.security.trust.TrustedCredentialTrustEngine; import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.signature.AbstractSignableXMLObject; @@ -164,29 +165,34 @@ public class PVP2Utils { } } + public static ExplicitKeySignatureTrustEngine getTrustEngine(ConfigurationProvider configuration) { + //Verify Signature + List keyInfoProvider = new ArrayList(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + + KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); + MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier()); + + return new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); + + } + public static void validateSignature(SignableXMLObject msg, ConfigurationProvider configuration) throws SecurityException, ValidationException { //Validate Signature SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); profileValidator.validate(msg.getSignature()); - - //Verify Signature - List keyInfoProvider = new ArrayList(); - keyInfoProvider.add(new DSAKeyValueProvider()); - keyInfoProvider.add(new RSAKeyValueProvider()); - keyInfoProvider.add(new InlineX509DataProvider()); - - KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( - keyInfoProvider); - - MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); - MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier()); - + CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); criteriaSet.add(new EntityIDCriteria(configuration.getPVP2IDPMetadataEntityName())); criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); - - ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); + + ExplicitKeySignatureTrustEngine trustEngine = getTrustEngine(configuration); trustEngine.validate(msg.getSignature(), criteriaSet); } diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java index 5265aed86..f121babc6 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java @@ -242,10 +242,10 @@ public class BuildMetadata extends HttpServlet { redirectBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_FRONT); spSSODescriptor.getSingleLogoutServices().add(redirectBindingService); - SingleLogoutService soapBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class); - soapBindingService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); - soapBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_BACK); - spSSODescriptor.getSingleLogoutServices().add(soapBindingService); +// SingleLogoutService soapBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class); +// soapBindingService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); +// soapBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_BACK); +// spSSODescriptor.getSingleLogoutServices().add(soapBindingService); spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java index 69adcc661..38c858918 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java @@ -78,7 +78,6 @@ public class SLOBasicServlet extends HttpServlet { LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); sloReq.setID(gen.generateIdentifier()); - request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, sloReq.getID()); sloReq.setIssueInstant(new DateTime()); NameID name = SAML2Utils.createSAMLObject(NameID.class); Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java index eb5752982..67921c689 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java @@ -120,6 +120,8 @@ public class SLOFrontChannelServlet extends SLOBasicServlet { //build SLO request to IDP LogoutRequest sloReq = createLogOutRequest(nameID, nameIDFormat, request); + request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, sloReq.getID()); + //send message sendMessage(request, response, sloReq, null); @@ -132,7 +134,7 @@ public class SLOFrontChannelServlet extends SLOBasicServlet { messageContext.setMetadataProvider(getConfig().getMetaDataProvier()); SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( - TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + PVP2Utils.getTrustEngine(getConfig())); SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule(); BasicSecurityPolicy policy = new BasicSecurityPolicy(); policy.getPolicyRules().add(signatureRule); @@ -141,9 +143,11 @@ public class SLOFrontChannelServlet extends SLOBasicServlet { policy); messageContext.setSecurityPolicyResolver(resolver); messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + + decode.decode(messageContext); signatureRule.evaluate(messageContext); - decode.decode(messageContext); + processMessage(request, response, messageContext.getInboundMessage(), messageContext.getRelayState()); -- cgit v1.2.3 From 0334cd30ddd9719b0801a274250be8476e0e95be Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Jun 2014 13:48:09 +0200 Subject: solve some SLO bugs --- .../moa/id/demoOA/servlet/pvp2/BuildMetadata.java | 2 +- .../moa/id/demoOA/servlet/pvp2/Index.java | 85 +++++++++++----------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java index 24ba26a59..65a4ab2a7 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java @@ -244,7 +244,7 @@ public class BuildMetadata extends HttpServlet { //set Single Log-Out service SingleLogoutService sloService = SAML2Utils.createSAMLObject(SingleLogoutService.class); - sloService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + sloService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); sloService.setLocation(serviceURL + Constants.SERVLET_PVPSINGLELOGOUT); spSSODescriptor.getSingleLogoutServices().add(sloService); diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java index c68ea9b1f..666ecaeee 100644 --- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java +++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java @@ -41,7 +41,11 @@ import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; +import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder; import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; +import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule; +import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.LogoutRequest; import org.opensaml.saml2.core.LogoutResponse; @@ -61,6 +65,9 @@ import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCredentialResolverFactory; import org.opensaml.security.MetadataCriteria; import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.ws.security.SecurityPolicyResolver; +import org.opensaml.ws.security.provider.BasicSecurityPolicy; +import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.opensaml.xml.parse.BasicParserPool; @@ -114,31 +121,27 @@ public class Index extends HttpServlet { return; } - if (method.equals("POST")) { + if (method.equals("GET")) { try { Configuration config = Configuration.getInstance(); //Decode with HttpPost Binding - HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); - BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); + HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( + new BasicParserPool()); + BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext - .setInboundMessageTransport(new HttpServletRequestAdapter( - request)); + .setInboundMessageTransport(new HttpServletRequestAdapter(request)); + decode.decode(messageContext); - - SignableXMLObject samlResponse = (SignableXMLObject) messageContext.getInboundMessage(); - - Signature sign = samlResponse.getSignature(); - if (sign == null) { - log.info("Only http POST Requests can be used"); - bean.setErrorMessage("Only http POST Requests can be used"); - setAnser(request, response, bean); - return; - } - //Validate Signature - SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); - profileValidator.validate(sign); + messageContext.setMetadataProvider(config.getMetaDataProvier()); + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName())); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); + MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(config.getMetaDataProvier()); //Verify Signature List keyInfoProvider = new ArrayList(); @@ -149,17 +152,28 @@ public class Index extends HttpServlet { KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( keyInfoProvider); - MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); - MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(config.getMetaDataProvier()); - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName())); - criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); - + ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); - trustEngine.validate(sign, criteriaSet); + + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + trustEngine); + SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule(); + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + policy.getPolicyRules().add(signedRole); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setSecurityPolicyResolver(resolver); + + messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + + signatureRule.evaluate(messageContext); + + SignableXMLObject samlResponse = (SignableXMLObject) messageContext.getInboundMessage(); + + + log.info("PVP2 statusrequest or statusresponse is valid"); @@ -232,7 +246,7 @@ public class Index extends HttpServlet { idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) { //Get the service address for the binding you wish to use - if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { redirectEndpoint = sss; } } @@ -251,20 +265,7 @@ public class Index extends HttpServlet { signer.setSigningCredential(authcredential); sloResp.setSignature(signer); - //generate Http-POST Binding message - VelocityEngine engine = new VelocityEngine(); - engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); - engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); - engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); - engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); - engine.setProperty("classpath.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); - engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, - "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); - engine.init(); - - HTTPPostEncoder encoder = new HTTPPostEncoder(engine, - "templates/pvp_postbinding_template.html"); + HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( response, true); BasicSAMLMessageContext context = new BasicSAMLMessageContext(); -- cgit v1.2.3 From f54870a55c9830caa2862d95e2e7f8f3cd6e0243 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 6 Jun 2014 13:49:25 +0200 Subject: final betaversion if MOA-ID-Auth Single LogOut --- .../auth/src/main/webapp/WEB-INF/urlrewrite.xml | 17 +- id/server/auth/src/main/webapp/WEB-INF/web.xml | 13 +- .../moa/id/auth/MOAIDAuthConstants.java | 4 + .../id/auth/servlet/IDPSingleLogOutServlet.java | 122 +++++++ .../moa/id/auth/servlet/LogOutServlet.java | 2 +- .../moa/id/auth/servlet/RedirectServlet.java | 22 +- .../moa/id/data/SLOInformationContainer.java | 16 +- .../moa/id/entrypoints/DispatcherServlet.java | 6 +- .../moa/id/moduls/AuthenticationManager.java | 170 ++++++++- .../gv/egovernment/moa/id/moduls/SSOManager.java | 26 ++ .../opemsaml/MOAStringRedirectDeflateEncoder.java | 71 ++++ .../moa/id/protocols/pvp2x/SingleLogOutAction.java | 380 ++++++++++----------- .../pvp2x/builder/SingleLogOutBuilder.java | 228 +++++++++++-- .../id/protocols/pvp2x/messages/MOAResponse.java | 8 +- .../pvp2x/utils/AssertionAttributeExtractor.java | 12 +- .../pvp2x/verification/SAMLVerificationEngine.java | 3 +- .../resources/properties/id_messages_de.properties | 7 +- .../resources/templates/slo_template.html | 57 ++++ 18 files changed, 888 insertions(+), 276 deletions(-) create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java create mode 100644 id/server/idserverlib/src/main/resources/resources/templates/slo_template.html diff --git a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml index 6da7396a1..23737452a 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml @@ -41,20 +41,29 @@ ^/pvp2/redirect$ - /dispatcher?mod=id_pvp2x&action=Redirect&%{query-string} + /dispatcher?mod=id_pvp2x&action=Redirect&endpointtype=idp&%{query-string} ^/pvp2/post$ - /dispatcher?mod=id_pvp2x&action=Post&%{query-string} + /dispatcher?mod=id_pvp2x&action=Post&endpointtype=idp&%{query-string} ^/pvp2/Soap$ - /dispatcher?mod=id_pvp2x&action=Soap + /dispatcher?mod=id_pvp2x&action=Soap&endpointtype=idp ^/pvp2/attributequery$ - /dispatcher?mod=id_pvp2x&action=AttributeQuery + /dispatcher?mod=id_pvp2x&action=AttributeQuery&endpointtype=idp + + ^/pvp2/sp/redirect$ + /dispatcher?mod=id_pvp2x&action=Redirect&endpointtype=sp&%{query-string} + + + ^/pvp2/sp/post$ + /dispatcher?mod=id_pvp2x&action=Post&endpointtype=sp&%{query-string} + + ^/stork2/StartAuthentication$ diff --git a/id/server/auth/src/main/webapp/WEB-INF/web.xml b/id/server/auth/src/main/webapp/WEB-INF/web.xml index 0ef8a568c..d60d73fd2 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/web.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/web.xml @@ -35,8 +35,15 @@ LogOut SSO LogOut at.gv.egovernment.moa.id.auth.servlet.LogOutServlet - 1 + + + IDPSLO + IDP-SLO + IDP Single LogOut Service + at.gv.egovernment.moa.id.auth.servlet.IDPSingleLogOutServlet + + VerifyIdentityLink VerifyIdentityLink @@ -170,6 +177,10 @@ LogOut /LogOut + + IDPSLO + /idpSingleLogout + VerifyIdentityLink /VerifyIdentityLink diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java index 6f83da367..e2c0c1f18 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java @@ -33,6 +33,10 @@ public interface MOAIDAuthConstants { public static final String PARAM_SSO = "SSO"; public static final String INTERFEDERATION_IDP = "interIDP"; + public static final String PARAM_SLOSTATUS = "status"; + public static final String SLOSTATUS_SUCCESS = "success"; + public static final String SLOSTATUS_ERROR = "error"; + /** servlet parameter "sourceID" */ public static final String PARAM_SOURCEID = "sourceID"; /** servlet parameter "BKUSelectionTemplate" */ diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java new file mode 100644 index 000000000..ac4e56023 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java @@ -0,0 +1,122 @@ +/* + * 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.auth.servlet; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.velocity.VelocityContext; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.moduls.AuthenticationManager; +import at.gv.egovernment.moa.id.moduls.SSOManager; +import at.gv.egovernment.moa.id.storage.AssertionStorage; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class IDPSingleLogOutServlet extends AuthServlet { + + private static final long serialVersionUID = -1301786072691577221L; + + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + Logger.debug("receive IDP SingleLogOut Request"); + SSOManager ssomanager = SSOManager.getInstance(); + String ssoid = ssomanager.getSSOSessionID(req); + + Object tokkenObj = req.getParameter(PARAM_SLOSTATUS); + String tokken = null; + String status = null; + if (tokkenObj != null && tokkenObj instanceof String) { + tokken = (String) tokkenObj; + try { + status = AssertionStorage.getInstance().get(tokken, String.class); + if (MiscUtil.isNotEmpty(status)) { + AssertionStorage.getInstance().remove(tokken); + + } + VelocityContext context = new VelocityContext(); + if (SLOSTATUS_SUCCESS.equals(status)) + context.put("successMsg", + MOAIDMessageProvider.getInstance().getMessage("slo.00", null)); + else + context.put("errorMsg", + MOAIDMessageProvider.getInstance().getMessage("slo.01", null)); + + ssomanager.printSingleLogOutInfo(context, resp); + + } catch (MOAIDException e) { + handleErrorNoRedirect(e.getMessage(), e, req, resp); + + } catch (MOADatabaseException e) { + handleErrorNoRedirect(e.getMessage(), e, req, resp); + + } + + } + + if (MiscUtil.isNotEmpty(status)) { + //print status information + + + } else if (MiscUtil.isNotEmpty(ssoid)) { + if (ssomanager.isValidSSOSession(ssoid, null)) { + + AuthenticationManager authmanager = AuthenticationManager.getInstance(); + String moaSessionID = AuthenticationSessionStoreage.getMOASessionSSOID(ssoid); + + if (MiscUtil.isNotEmpty(moaSessionID)) { + AuthenticationSession authSession; + try { + authSession = AuthenticationSessionStoreage + .getSession(moaSessionID); + if(authSession != null) { + authmanager.performSingleLogOut(req, resp, authSession, null); + + } + + } catch (MOADatabaseException e) { + //TODO: insert error Handling + + } catch (MOAIDException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java index 9b300578a..d7de985a4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java @@ -109,7 +109,7 @@ public class LogOutServlet extends AuthServlet { RequestStorage.removePendingRequest(AuthenticationSessionStoreage.getPendingRequestID(moasessionid)); - authmanager.logout(req, resp, moasessionid); + authmanager.performOnlyIDPLogOut(req, resp, moasessionid); Logger.info("User with SSO Id " + ssoid + " is logged out and get redirect to "+ redirectUrl); } else { Logger.info("No active SSO session found. User is maybe logout already and get redirect to "+ redirectUrl); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java index 57755ca9f..6e1811c8b 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java @@ -46,6 +46,8 @@ public class RedirectServlet extends AuthServlet{ public static final String REDIRCT_PARAM_URL = "redirecturl"; + private static final String DEFAULT_REDIRECTTARGET = "_parent"; + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -55,16 +57,10 @@ public class RedirectServlet extends AuthServlet{ String target = req.getParameter(PARAM_TARGET); String artifact = req.getParameter(PARAM_SAMLARTIFACT); String interIDP = req.getParameter(INTERFEDERATION_IDP); - - if (MiscUtil.isEmpty(artifact) && MiscUtil.isEmpty(interIDP)) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Parameters not valid"); - return; - } - Logger.debug("Check URL against online-applications"); OnlineApplication oa = null; - String redirectTarget = "_parent"; + String redirectTarget = DEFAULT_REDIRECTTARGET; try { oa = ConfigurationDBRead.getActiveOnlineApplication(url); if (oa == null) { @@ -118,10 +114,16 @@ public class RedirectServlet extends AuthServlet{ resp.addHeader("Location", url); - } else { - resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Parameters not valid"); - return; + } else { + Logger.debug("Redirect to " + url); + String redirect_form = RedirectFormBuilder.buildLoginForm(url, DEFAULT_REDIRECTTARGET); + resp.setContentType("text/html;charset=UTF-8"); + resp.setStatus(HttpServletResponse.SC_OK); + PrintWriter out = new PrintWriter(resp.getOutputStream()); + out.write(redirect_form); + out.flush(); + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java index df195c0de..d1e04e107 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java @@ -24,9 +24,12 @@ package at.gv.egovernment.moa.id.data; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map.Entry; +import java.util.Set; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.NameID; @@ -135,17 +138,12 @@ public class SLOInformationContainer implements Serializable { } } - public String getNextFrontChannelOA() { - Iterator interator = activeFrontChannalOAs.keySet().iterator(); - if (interator.hasNext()) - return interator.next(); - - else - return null; + public boolean hasFrontChannelOA() { + return !activeFrontChannalOAs.isEmpty(); } - public SLOInformationImpl getFrontChannelOASessionDescripten(String oaID) { - return activeFrontChannalOAs.get(oaID); + public Set> getFrontChannelOASessionDescriptions() { + return activeFrontChannalOAs.entrySet(); } public void removeFrontChannelOA(String oaID) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java index a3827ab73..0cbe749e0 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java @@ -143,7 +143,7 @@ public class DispatcherServlet extends AuthServlet{ //remove MOASession AuthenticationSession moaSession = AuthenticationSessionStoreage.getSessionWithPendingRequestID(pendingRequestID); - AuthenticationManager.getInstance().logout(req, resp, moaSession.getSessionID()); + AuthenticationManager.getInstance().performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); return; } @@ -468,12 +468,12 @@ public class DispatcherServlet extends AuthServlet{ } catch (AuthenticationException e) { Logger.warn("SSO Session information can not be stored -> SSO is not enabled!"); - authmanager.logout(req, resp, moasessionID); + authmanager.performOnlyIDPLogOut(req, resp, moasessionID); isSSOSession = false; } } else { - authmanager.logout(req, resp, moasessionID); + authmanager.performOnlyIDPLogOut(req, resp, moasessionID); } //Advanced statistic logging diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java index 5a06b3ecd..ee26d9223 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java @@ -24,13 +24,21 @@ package at.gv.egovernment.moa.id.moduls; import java.io.IOException; import java.io.PrintWriter; +import java.io.StringWriter; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; import org.joda.time.DateTime; import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; @@ -38,6 +46,8 @@ import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.NameIDPolicy; import org.opensaml.saml2.core.NameIDType; @@ -45,12 +55,15 @@ import org.opensaml.saml2.core.RequestedAuthnContext; import org.opensaml.saml2.core.Subject; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCredentialResolverFactory; import org.opensaml.security.MetadataCriteria; import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.ws.soap.common.SOAPException; +import org.opensaml.xml.XMLObject; import org.opensaml.xml.security.CriteriaSet; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.criteria.EntityIDCriteria; @@ -64,19 +77,32 @@ import at.gv.egovernment.moa.id.auth.exception.BuildException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.parser.StartAuthentificationParameterParser; import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; +import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; +import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.SLOInformationContainer; +import at.gv.egovernment.moa.id.data.SLOInformationImpl; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; 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.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.MOASAMLSOAPClient; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.id.storage.AssertionStorage; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MessageProvider; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.StringUtils; @@ -138,7 +164,149 @@ public class AuthenticationManager extends AuthServlet { return false; } - public void logout(HttpServletRequest request, + public void performSingleLogOut(HttpServletRequest httpReq, + HttpServletResponse httpResp, AuthenticationSession session, PVPTargetConfiguration pvpReq) throws MOAIDException { + String pvpSLOIssuer = null; + String inboundRelayState = null; + + if (pvpReq != null) { + MOARequest samlReq = (MOARequest) pvpReq.getRequest(); + LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); + pvpSLOIssuer = logOutReq.getIssuer().getValue(); + inboundRelayState = samlReq.getRelayState(); + } + + SSOManager ssomanager = SSOManager.getInstance(); + + //store active OAs to SLOContaine + List dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); + List dbIDPs = AuthenticationSessionStoreage.getAllActiveIDPsFromMOASession(session); + SLOInformationContainer sloContainer = new SLOInformationContainer(); + sloContainer.setSloRequest(pvpReq); + sloContainer.parseActiveIDPs(dbIDPs, pvpSLOIssuer); + sloContainer.parseActiveOAs(dbOAs, pvpSLOIssuer); + + //terminate MOASession + try { + AuthenticationSessionStoreage.destroySession(session.getSessionID()); + ssomanager.deleteSSOSessionID(httpReq, httpResp); + + } catch (MOADatabaseException e) { + Logger.warn("Delete MOASession FAILED."); + sloContainer.putFailedOA(AuthConfigurationProvider.getInstance().getPublicURLPrefix()); + + } + + //start service provider back channel logout process + Iterator nextOAInterator = sloContainer.getNextBackChannelOA(); + while (nextOAInterator.hasNext()) { + SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next()); + LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); + + try { + List soapResp = MOASAMLSOAPClient.send(sloDescr.getServiceURL(), sloReq); + + LogoutResponse sloResp = null; + for (XMLObject el : soapResp) { + if (el instanceof LogoutResponse) + sloResp = (LogoutResponse) el; + } + + if (sloResp == null) { + Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() + + " FAILED. NO LogOut response received."); + sloContainer.putFailedOA(sloReq.getIssuer().getValue()); + + } + + SingleLogOutBuilder.checkStatusCode(sloContainer, sloResp); + + } catch (SOAPException e) { + Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() + + " FAILED.", e); + sloContainer.putFailedOA(sloReq.getIssuer().getValue()); + + } catch (SecurityException e) { + Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() + + " FAILED.", e); + sloContainer.putFailedOA(sloReq.getIssuer().getValue()); + + } + } + + //start service provider front channel logout process + try { + if (sloContainer.hasFrontChannelOA()) { + String relayState = Random.nextRandom(); + + Collection> sloDescr = sloContainer.getFrontChannelOASessionDescriptions(); + List sloReqList = new ArrayList(); + for (Entry el : sloDescr) { + LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(el.getValue()); + try { + sloReqList.add(SingleLogOutBuilder.getFrontChannelSLOMessageURL(el.getValue().getServiceURL(), el.getValue().getBinding(), + sloReq, httpReq, httpResp, relayState)); + + } catch (Exception e) { + Logger.warn("Failed to build SLO request for OA:" + el.getKey()); + sloContainer.putFailedOA(el.getKey()); + + } + } + + AssertionStorage.getInstance().put(relayState, sloContainer); + + VelocityContext context = new VelocityContext(); + context.put("redirectURLs", sloReqList); + ssomanager.printSingleLogOutInfo(context, httpResp); + + + } else { + if (pvpReq != null) { + //send SLO response to SLO request issuer + SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); + LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, sloContainer.getSloFailedOAs()); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, inboundRelayState); + + } else { + //print SLO information directly + VelocityContext context = new VelocityContext(); + if (sloContainer.getSloFailedOAs() == null || + sloContainer.getSloFailedOAs().size() == 0) + context.put("successMsg", + MessageProvider.getInstance().getMessage("slo.00", null)); + else + context.put("errorMsg", + MessageProvider.getInstance().getMessage("slo.01", null)); + ssomanager.printSingleLogOutInfo(context, httpResp); + + } + + } + + } catch (MOADatabaseException e) { + Logger.error("MOA AssertionDatabase ERROR", e); + if (pvpReq != null) { + SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); + LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, inboundRelayState); + + }else { + //print SLO information directly + VelocityContext context = new VelocityContext(); + context.put("errorMsg", + MessageProvider.getInstance().getMessage("slo.01", null)); + ssomanager.printSingleLogOutInfo(context, httpResp); + + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void performOnlyIDPLogOut(HttpServletRequest request, HttpServletResponse response, String moaSessionID) { Logger.info("Logout"); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java index f4f89a4ba..02e252412 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java @@ -22,17 +22,22 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.moduls; +import java.io.StringWriter; import java.util.List; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; import org.hibernate.Query; import org.hibernate.Session; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils; import at.gv.egovernment.moa.id.commons.db.dao.session.AuthenticatedSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; @@ -42,6 +47,7 @@ import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; @@ -267,6 +273,26 @@ public class SSOManager { } + public void printSingleLogOutInfo(VelocityContext context, HttpServletResponse httpResp) throws MOAIDException { + try { + Logger.trace("Initialize VelocityEngine..."); + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/slo_template.html"); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + httpResp.setContentType("text/html;charset=UTF-8"); + httpResp.getOutputStream().write(writer.toString().getBytes()); + + } catch (Exception e) { + Logger.error("Single LogOut from can not created.", e); + throw new MOAIDException("Create Single LogOut information FAILED.", null, e); + } + + } + + private String getValueFromCookie(HttpServletRequest httpReq, String cookieName) { Cookie[] cookies = httpReq.getCookies(); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java new file mode 100644 index 000000000..ece1a805d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java @@ -0,0 +1,71 @@ +/* + * 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.opemsaml; + +import org.opensaml.common.binding.SAMLMessageContext; +import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; +import org.opensaml.ws.message.MessageContext; +import org.opensaml.ws.message.encoder.MessageEncodingException; + +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +public class MOAStringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { + + private String redirectURL = null; + + public void encode(MessageContext messageContext) + throws MessageEncodingException { + if (!(messageContext instanceof SAMLMessageContext)) { + Logger.error("Invalid message context type, this encoder only support SAMLMessageContext"); + throw new MessageEncodingException( + "Invalid message context type, this encoder only support SAMLMessageContext"); + } + + SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; + + String endpointURL = getEndpointURL(samlMsgCtx).buildURL(); + + setResponseDestination(samlMsgCtx.getOutboundSAMLMessage(), endpointURL); + + removeSignature(samlMsgCtx); + + String encodedMessage = deflateAndBase64Encode(samlMsgCtx + .getOutboundSAMLMessage()); + + redirectURL = buildRedirectURL(samlMsgCtx, endpointURL, + encodedMessage); + } + + /** + * @return the redirectURL + */ + public String getRedirectURL() { + return redirectURL; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java index 92441e663..46e02d048 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java @@ -22,26 +22,50 @@ */ package at.gv.egovernment.moa.id.protocols.pvp2x; +import java.io.Serializable; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang.SerializationUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.LogoutRequest; import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.ws.soap.common.SOAPException; import org.opensaml.xml.XMLObject; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.servlet.RedirectServlet; +import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils; +import at.gv.egovernment.moa.id.commons.db.dao.session.AssertionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; @@ -50,9 +74,11 @@ import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; +import at.gv.egovernment.moa.id.moduls.AuthenticationManager; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IRequest; import at.gv.egovernment.moa.id.moduls.SSOManager; +import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; @@ -60,12 +86,17 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SLOException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOAResponse; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.MOASAMLSOAPClient; import at.gv.egovernment.moa.id.storage.AssertionStorage; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MessageProvider; import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moa.util.URLEncoder; /** * @author tlenz @@ -83,16 +114,16 @@ public class SingleLogOutAction implements IAction { PVPTargetConfiguration pvpReq = (PVPTargetConfiguration) req; - if (pvpReq.getRequest() instanceof MOARequest) { + if (pvpReq.getRequest() instanceof MOARequest && + ((MOARequest)pvpReq.getRequest()).getSamlRequest() instanceof LogoutRequest) { + Logger.debug("Process Single LogOut request"); MOARequest samlReq = (MOARequest) pvpReq.getRequest(); - if (samlReq.getSamlRequest() instanceof LogoutRequest) { - Logger.debug("Process Single LogOut request"); - LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); + LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); - AuthenticationSession session = - AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID( - logOutReq.getIssuer().getValue(), - logOutReq.getNameID().getValue()); + AuthenticationSession session = + AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID( + logOutReq.getIssuer().getValue(), + logOutReq.getNameID().getValue()); if (session == null) { Logger.warn("Can not find active SSO session with nameID " @@ -105,7 +136,7 @@ public class SingleLogOutAction implements IAction { Logger.warn("Can not find active Session. Single LogOut not possible!"); SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } else { @@ -117,103 +148,150 @@ public class SingleLogOutAction implements IAction { Logger.warn("Can not find active Session. Single LogOut not possible!"); SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } } } - //store active OAs to SLOContaine - List dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); - List dbIDPs = AuthenticationSessionStoreage.getAllActiveIDPsFromMOASession(session); - SLOInformationContainer sloContainer = new SLOInformationContainer(); - sloContainer.setSloRequest(pvpReq); - sloContainer.parseActiveIDPs(dbIDPs, logOutReq.getIssuer().getValue()); - sloContainer.parseActiveOAs(dbOAs, logOutReq.getIssuer().getValue()); - - //terminate MOASession - try { - AuthenticationSessionStoreage.destroySession(session.getSessionID()); - - } catch (MOADatabaseException e) { - Logger.warn("Delete MOASession FAILED."); - sloContainer.putFailedOA(AuthConfigurationProvider.getInstance().getPublicURLPrefix()); - - } - - //start service provider back channel logout process - Iterator nextOAInterator = sloContainer.getNextBackChannelOA(); - while (nextOAInterator.hasNext()) { - SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next()); - LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); - - try { - List soapResp = MOASAMLSOAPClient.send(sloDescr.getServiceURL(), sloReq); - - LogoutResponse sloResp = null; - for (XMLObject el : soapResp) { - if (el instanceof LogoutResponse) - sloResp = (LogoutResponse) el; - } - - if (sloResp == null) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED. NO LogOut response received."); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.performSingleLogOut(httpReq, httpResp, session, pvpReq); - } - - checkStatusCode(sloContainer, sloResp); - - } catch (SOAPException e) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED.", e); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); - - } catch (SecurityException e) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED.", e); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); - - } - } - - //start service provider front channel logout process - try { - doFrontChannelLogOut(sloContainer, httpReq, httpResp); - - } catch (MOADatabaseException e) { - Logger.error("MOA AssertionDatabase ERROR", e); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); - return null; - - } - - } else if (samlReq.getSamlRequest() instanceof LogoutResponse) { + } else if (pvpReq.getRequest() instanceof MOAResponse && + ((MOAResponse)pvpReq.getRequest()).getResponse() instanceof LogoutResponse) { Logger.debug("Process Single LogOut response"); - LogoutResponse logOutResp = (LogoutResponse) samlReq.getSamlRequest(); + LogoutResponse logOutResp = (LogoutResponse) ((MOAResponse)pvpReq.getRequest()).getResponse(); - try { - if (MiscUtil.isEmpty(samlReq.getRelayState())) { + try { + String relayState = pvpReq.getRequest().getRelayState(); + if (MiscUtil.isEmpty(relayState)) { Logger.warn("SLO Response from " + logOutResp.getIssuer().getValue() + " has no SAML2 RelayState."); throw new SLOException("pvp2.19", null); } - SLOInformationContainer sloContainer = - AssertionStorage.getInstance().get(samlReq.getRelayState(), SLOInformationContainer.class); - checkStatusCode(sloContainer, logOutResp); - sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue()); - doFrontChannelLogOut(sloContainer, httpReq, httpResp); + Session session = MOASessionDBUtils.getCurrentSession(); + boolean storageSuccess = false; + int counter = 0; + + //TODO: add counter to prevent deadlock + + while (!storageSuccess) { + Transaction tx = session.beginTransaction(); + + List result; + Query query = session.getNamedQuery("getAssertionWithArtifact"); + query.setParameter("artifact", relayState); + result = query.list(); + Logger.trace("Found entries: " + result.size()); + + //Assertion requires an unique artifact + if (result.size() != 1) { + Logger.trace("No entries found."); + throw new MOADatabaseException("No sessioninformation found with this ID"); + } + + AssertionStore element = (AssertionStore) result.get(0); + Object data = SerializationUtils.deserialize(element.getAssertion()); + + if (data instanceof SLOInformationContainer) { + SLOInformationContainer sloContainer = (SLOInformationContainer) data; + + //check status + SingleLogOutBuilder.checkStatusCode(sloContainer, logOutResp); + + if (sloContainer.hasFrontChannelOA()) { + try { + //some response are open + byte[] serializedSLOContainer = SerializationUtils.serialize((Serializable) sloContainer); + element.setAssertion(serializedSLOContainer); + element.setType(sloContainer.getClass().getName()); + + session.saveOrUpdate(element); + tx.commit(); + + //sloContainer could be stored to database + storageSuccess = true; + + } catch(HibernateException e) { + tx.rollback(); + + counter++; + Logger.debug("SLOContainter could not stored to database. Wait some time and restart storage process ... "); + java.util.Random rand = new java.util.Random(); + + try { + Thread.sleep(rand.nextInt(20)*10); + + } catch (InterruptedException e1) { + Logger.warn("Thread could not stopped. ReStart storage process immediately", e1); + } + } + + } else { + //last response received. + try { + session.delete(element); + tx.commit(); + + } catch(HibernateException e) { + tx.rollback(); + Logger.error("SLOContainter could not deleted from database. "); + + } + + storageSuccess = true; + String redirectURL = null; + if (sloContainer.getSloRequest() != null) { + //send SLO response to SLO request issuer + SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(sloContainer.getSloRequest()); + LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, sloContainer.getSloRequest(), sloContainer.getSloFailedOAs()); + redirectURL = SingleLogOutBuilder.getFrontChannelSLOMessageURL(sloService, message, httpReq, httpResp, sloContainer.getSloRequest().getRequest().getRelayState()); + + } else { + //print SLO information directly + redirectURL = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/idpSingleLogout"; + + String artifact = Random.nextRandom(); + + String statusCode = null; + if (sloContainer.getSloFailedOAs() == null || + sloContainer.getSloFailedOAs().size() == 0) + statusCode = SLOSTATUS_SUCCESS; + else + statusCode = SLOSTATUS_ERROR; + + AssertionStorage.getInstance().put(artifact, statusCode); + redirectURL = addURLParameter(redirectURL, PARAM_SLOSTATUS, artifact); + + } + //redirect to Redirect Servlet + String url = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/RedirectServlet"; + url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(redirectURL, "UTF-8")); + url = httpResp.encodeRedirectURL(url); + + httpResp.setContentType("text/html"); + httpResp.setStatus(302); + httpResp.addHeader("Location", url); + + } + } else { + Logger.warn("Sessioninformation Cast-Exception by using Artifact=" + relayState); + throw new MOADatabaseException("Sessioninformation Cast-Exception"); + + } + } } catch (MOADatabaseException e) { Logger.error("MOA AssertionDatabase ERROR", e); throw new SLOException("pvp2.19", null); + } catch (UnsupportedEncodingException e) { + Logger.error("Finale SLO redirct not possible.", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + } } else { @@ -221,13 +299,7 @@ public class SingleLogOutAction implements IAction { throw new MOAIDException("pvp2.13", null); } - - } else { - Logger.error("Process SingleLogOutAction but request is NOT of type MOARequest."); - throw new MOAIDException("pvp2.13", null); - - } - + return null; } @@ -248,120 +320,12 @@ public class SingleLogOutAction implements IAction { return PVP2XProtocol.SINGLELOGOUT; } - private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { - Status status = logOutResp.getStatus(); - if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { - String message = " Message: "; - if (status.getStatusMessage() != null) - message += status.getStatusMessage().getMessage(); - Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() - + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() - + message + ")"); - sloContainer.putFailedOA(logOutResp.getIssuer().getValue()); - - } else - Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS"); - + protected static String addURLParameter(String url, String paramname, + String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; } - - private void doFrontChannelLogOut(SLOInformationContainer sloContainer, - HttpServletRequest httpReq, HttpServletResponse httpResp - ) throws MOAIDException, MOADatabaseException { - String nextOA = sloContainer.getNextFrontChannelOA(); - if (MiscUtil.isNotEmpty(nextOA)) { - SLOInformationImpl sloDescr = sloContainer.getFrontChannelOASessionDescripten(nextOA); - LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); - String relayState = Random.nextRandom(); - - AssertionStorage.getInstance().put(relayState, sloContainer); - - sendFrontChannelSLOMessage(sloDescr.getServiceURL(), sloDescr.getBinding(), - sloReq, httpReq, httpResp, relayState); - - } else { - //send SLO response to SLO request issuer - PVPTargetConfiguration pvpReq = sloContainer.getSloRequest(); - MOARequest samlReq = (MOARequest) pvpReq.getRequest(); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, sloContainer.getSloFailedOAs()); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); - - } - } - - /** - * @param serviceURL - * @param binding - * @param sloReq - * @param httpReq - * @param httpResp - * @param relayState - */ - private void sendFrontChannelSLOMessage(String serviceURL, String bindingType, - RequestAbstractType sloReq, HttpServletRequest httpReq, - HttpServletResponse httpResp, String relayState) throws MOAIDException { - IEncoder binding = null; - if (bindingType.equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = new RedirectBinding(); - - } else if (bindingType.equals( - SAMLConstants.SAML2_POST_BINDING_URI)) { - binding = new PostBinding(); - - } - - if (binding == null) { - throw new BindingNotSupportedException(bindingType); - } - - try { - binding.encodeRequest(httpReq, httpResp, sloReq, - serviceURL, relayState); - - } 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); - - } - - } - - private void sendFrontChannelSLOMessage(SingleLogoutService consumerService, - LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp, - String relayState) throws MOAIDException { - IEncoder binding = null; - if (consumerService.getBinding().equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = new RedirectBinding(); - - } 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, sloResp, - consumerService.getLocation(), relayState); - - } 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); - - } - - } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java index 7aa860c5c..eeb1dd104 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java @@ -22,31 +22,53 @@ */ package at.gv.egovernment.moa.id.protocols.pvp2x.builder; +import java.security.NoSuchAlgorithmException; import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.joda.time.DateTime; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.LogoutRequest; import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.StatusMessage; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.SSODescriptor; import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; +import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; +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.config.PVPConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.logging.Logger; @@ -57,9 +79,141 @@ import at.gv.egovernment.moa.logging.Logger; */ public class SingleLogOutBuilder { - public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException { + public static void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { + Status status = logOutResp.getStatus(); + if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + String message = " Message: "; + if (status.getStatusMessage() != null) + message += status.getStatusMessage().getMessage(); + Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() + + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() + + message + ")"); + sloContainer.putFailedOA(logOutResp.getIssuer().getValue()); + + } else + sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue()); + Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS"); + + } + + /** + * @param serviceURL + * @param binding + * @param sloReq + * @param httpReq + * @param httpResp + * @param relayState + * @return + */ + public static String getFrontChannelSLOMessageURL(String serviceURL, String bindingType, + RequestAbstractType sloReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, String relayState) throws MOAIDException { + + try { + X509Credential credentials = CredentialProvider + .getIDPAssertionSigningCredential(); + + Logger.debug("create SAML RedirectBinding response"); + + MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder(); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + SingleLogoutService service = new SingleLogoutServiceBuilder() + .buildObject(); + service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + service.setLocation(serviceURL); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloReq); + context.setRelayState(relayState); + + encoder.encode(context); + + return encoder.getRedirectURL(); + + } catch (MessageEncodingException e) { + Logger.error("Message Encoding exception", e); + throw new MOAIDException("pvp2.01", null, e); + + } + } + + public static String getFrontChannelSLOMessageURL(SingleLogoutService service, + StatusResponseType sloResp, HttpServletRequest httpReq, + HttpServletResponse httpResp, String relayState) throws MOAIDException { + + try { + X509Credential credentials = CredentialProvider + .getIDPAssertionSigningCredential(); + + Logger.debug("create SAML RedirectBinding response"); + + MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder(); + BasicSAMLMessageContext context = new BasicSAMLMessageContext(); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloResp); + context.setRelayState(relayState); + + encoder.encode(context); + + return encoder.getRedirectURL(); + + } catch (MessageEncodingException e) { + Logger.error("Message Encoding exception", e); + throw new MOAIDException("pvp2.01", null, e); + + } + } + + public static void sendFrontChannelSLOMessage(SingleLogoutService consumerService, + LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp, + String relayState) throws MOAIDException { + IEncoder binding = null; + if (consumerService.getBinding().equals( + SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + binding = new RedirectBinding(); + + } 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, sloResp, + consumerService.getLocation(), relayState); + + } 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); + + } + } + + + public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException, MOAIDException { LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); + SecureRandomIdentifierGenerator gen; + try { + gen = new SecureRandomIdentifierGenerator(); + sloReq.setID(gen.generateIdentifier()); + + } catch (NoSuchAlgorithmException e) { + Logger.error("Internal server error", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + + } + + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); issuer.setFormat(NameID.ENTITY); @@ -76,14 +230,9 @@ public class SingleLogOutBuilder { return sloReq; } - public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException { - LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); - issuer.setFormat(NameID.ENTITY); - sloResp.setIssuer(issuer); - sloResp.setIssueInstant(new DateTime()); - sloResp.setDestination(sloService.getLocation()); + public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { + LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); + Status status = SAML2Utils.createSAMLObject(Status.class); StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class); @@ -95,14 +244,8 @@ public class SingleLogOutBuilder { return sloResp; } - public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List failedOAs) throws ConfigurationException { - LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); - issuer.setFormat(NameID.ENTITY); - sloResp.setIssuer(issuer); - sloResp.setIssueInstant(new DateTime()); - sloResp.setDestination(sloService.getLocation()); + public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List failedOAs) throws MOAIDException { + LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); Status status; if (failedOAs == null || failedOAs.size() == 0) { @@ -123,6 +266,37 @@ public class SingleLogOutBuilder { } + private static LogoutResponse buildBasicResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { + LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + issuer.setFormat(NameID.ENTITY); + sloResp.setIssuer(issuer); + sloResp.setIssueInstant(new DateTime()); + sloResp.setDestination(sloService.getLocation()); + + SecureRandomIdentifierGenerator gen; + try { + gen = new SecureRandomIdentifierGenerator(); + sloResp.setID(gen.generateIdentifier()); + + } catch (NoSuchAlgorithmException e) { + Logger.error("Internal server error", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + + } + + if (spRequest.getRequest() instanceof MOARequest && + ((MOARequest)spRequest.getRequest()).getSamlRequest() instanceof LogoutRequest) { + LogoutRequest sloReq = (LogoutRequest) ((MOARequest)spRequest.getRequest()).getSamlRequest(); + sloResp.setInResponseTo(sloReq.getID()); + + } + + return sloResp; + + } + public static SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException { try { EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID); @@ -140,19 +314,19 @@ public class SingleLogOutBuilder { ) sloService = el; - else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) - && ( - (sloService != null - && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI) - && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) - || sloService == null) - ) - sloService = el; +// else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) +// && ( +// (sloService != null +// && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI) +// && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) +// || sloService == null) +// ) +// sloService = el; } if (sloService == null) { - Logger.error("Found no SLO ServiceDescriptor in Metadata"); - throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null); + Logger.error("Found no valid SLO ServiceDescriptor in Metadata"); + throw new NOSLOServiceDescriptorException("NO valid SLO ServiceDescriptor", null); } return sloService; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java index 870273cf3..f2512b122 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java @@ -23,7 +23,7 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.messages; import org.opensaml.Configuration; -import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.xml.io.Unmarshaller; import org.opensaml.xml.io.UnmarshallerFactory; import org.opensaml.xml.io.UnmarshallingException; @@ -35,16 +35,16 @@ public class MOAResponse extends InboundMessage { private static final long serialVersionUID = -1133012928130138501L; - public MOAResponse(Response response) { + public MOAResponse(StatusResponseType response) { setSAMLMessage(response.getDOM()); } - public Response getResponse() { + public StatusResponseType getResponse() { UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage()); try { - return (Response) unmashaller.unmarshall(getInboundMessage()); + return (StatusResponseType) unmashaller.unmarshall(getInboundMessage()); } catch (UnmarshallingException e) { Logger.warn("AuthnResponse Unmarshaller error", e); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java index 61b481447..ee0088576 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java @@ -28,6 +28,7 @@ import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnStatement; import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.core.Subject; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionAttributeExtractorExeption; @@ -38,15 +39,16 @@ public class AssertionAttributeExtractor { private Assertion assertion = null; - public AssertionAttributeExtractor(Response samlResponse) throws AssertionAttributeExtractorExeption { - if (samlResponse != null) { - if (samlResponse.getAssertions().size() == 0) + public AssertionAttributeExtractor(StatusResponseType samlResponse) throws AssertionAttributeExtractorExeption { + if (samlResponse != null && samlResponse instanceof Response) { + List assertions = ((Response) samlResponse).getAssertions(); + if (assertions.size() == 0) throw new AssertionAttributeExtractorExeption("Assertion"); - else if (samlResponse.getAssertions().size() > 1) + else if (assertions.size() > 1) Logger.warn("Found more then ONE PVP2.1 assertions. Only the First is used."); - assertion = samlResponse.getAssertions().get(0); + assertion = assertions.get(0); } else throw new AssertionAttributeExtractorExeption(); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java index 6388042d9..3be5df917 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java @@ -32,6 +32,7 @@ import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.encryption.Decrypter; import org.opensaml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver; import org.opensaml.saml2.metadata.IDPSSODescriptor; @@ -76,7 +77,7 @@ public class SAMLVerificationEngine { } - public void verifyResponse(Response samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { + public void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); try { profileValidator.validate(samlObj.getSignature()); diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties index c8cca157d..9aab22ef5 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties @@ -243,9 +243,9 @@ pvp2.16=Fehler beim verschl\u00FCsseln der PVP2 Assertion pvp2.17=Der QAA Level {0} entspricht nicht dem angeforderten QAA Level {1} pvp2.18=Es konnten nicht alle Single Sign-On Sessions beendet werden. pvp2.19=Der Single LogOut Vorgang musste wegen eines unkorregierbaren Fehler abgebrochen werden. -pvp2.20=Für die im Request angegebene EntityID konnten keine g\u00FCltigen Metadaten gefunden werden. +pvp2.20=F\u00FCr die im Request angegebene EntityID konnten keine g\u00FCltigen Metadaten gefunden werden. pvp2.21=Die Signature des Requests konnte nicht g\u00FCltig validiert werden. -pvp2.22=Der Request konnte nicht g\u00FCltig validiert werden (Fehler={0}). +pvp2.22=Der Request konnte nicht g\u00FCltig validiert werden (Fehler\={0}). oauth20.01=Fehlerhafte redirect url oauth20.02=Fehlender Parameter "{0}" @@ -256,3 +256,6 @@ oauth20.06=Die angegebene OA kann nicht verwendet werden oauth20.07=Angeforderter grant_type ist nicht erlaubt oauth20.08=Nicht berechtigt f\u00FCr Token-Request oauth20.09=Zertifikat fuer JSON Web-Token ist falsch konfiguriert. Fehler bei "{0}" + +slo.00=Sie konnten erfolgreich von allen Online-Applikation abgemeldet werden. +slo.01=Sie konnten NICHT erfolgreich von allen Online-Applikationen abgemeldet werden\!
Bitte schlie\u00DFen Sie aus sicherheitsgr\u00FCnden Ihren Browser. diff --git a/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html new file mode 100644 index 000000000..16c9e87eb --- /dev/null +++ b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html @@ -0,0 +1,57 @@ + + + + + +

MOA-ID Single LogOut Information

+ + + + #if($errorMsg) +
+

$errorMsg

+
+ #end + + #if($successMsg) +
+

$successMsg

+
+ #end + + #if($redirectURLs) +
+

+ Sie werden von allen Online-Applikationen abgemeldet.
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen. +

+
+ #end + + #foreach( $el in $redirectURLs ) + + #end + + + + \ No newline at end of file -- cgit v1.2.3 From ebe5ab97d0445cc3c882ffa956df17dcd8d2818d Mon Sep 17 00:00:00 2001 From: Bojan Suzic Date: Fri, 6 Jun 2014 14:16:03 +0200 Subject: adjusting maven config --- id/server/idserverlib/pom.xml | 5 ++++- id/server/moa-id-commons/pom.xml | 1 + spss/server/serverlib/pom.xml | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml index 1f392f7ec..51e6395fa 100644 --- a/id/server/idserverlib/pom.xml +++ b/id/server/idserverlib/pom.xml @@ -241,11 +241,14 @@ --> - + + eu.stork DocumentService diff --git a/id/server/moa-id-commons/pom.xml b/id/server/moa-id-commons/pom.xml index 02915ef18..67a2231a6 100644 --- a/id/server/moa-id-commons/pom.xml +++ b/id/server/moa-id-commons/pom.xml @@ -72,6 +72,7 @@ MOA moa-common jar + ${moa-commons-version} diff --git a/spss/server/serverlib/pom.xml b/spss/server/serverlib/pom.xml index 3c29cd88c..c8e5022eb 100644 --- a/spss/server/serverlib/pom.xml +++ b/spss/server/serverlib/pom.xml @@ -128,6 +128,7 @@ MOA moa-common jar + ${moa-commons-version} -- cgit v1.2.3 From 205061d2ac31d0c36909e37ab3e5db98725610aa Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 10 Jun 2014 08:28:56 +0200 Subject: use ServletContextPath from configuration --- .../java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java index ee26d9223..a7eb51877 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java @@ -364,7 +364,8 @@ public class AuthenticationManager extends AuthServlet { throws ServletException, IOException, MOAIDException { String form = SendAssertionFormBuilder.buildForm(target.requestedModule(), - target.requestedAction(), target.getRequestID(), oaParam, request.getContextPath()); + target.requestedAction(), target.getRequestID(), oaParam, + AuthConfigurationProvider.getInstance().getPublicURLPrefix()); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = new PrintWriter(response.getOutputStream()); -- cgit v1.2.3 From d515dc2465a1daf5baa88c3059b9c2b0ea968df0 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 10 Jun 2014 08:30:53 +0200 Subject: Load SLO template from configuration directory --- .../conf/moa-id/htmlTemplates/slo_template.html | 438 +++++++++++++++++++ .../conf/moa-id/htmlTemplates/slo_template.html | 438 +++++++++++++++++++ .../gv/egovernment/moa/id/moduls/SSOManager.java | 67 ++- .../resources/templates/slo_template.html | 463 +++++++++++++++++++-- 4 files changed, 1356 insertions(+), 50 deletions(-) create mode 100644 id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html create mode 100644 id/server/doc/conf/moa-id/htmlTemplates/slo_template.html diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html b/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html new file mode 100644 index 000000000..a652855c4 --- /dev/null +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html @@ -0,0 +1,438 @@ + + + + + + + + + Single LogOut Vorgang ... + + + + + +
+
+

MOA-ID Single LogOut Information

+
+
+ + #if($errorMsg) +
+

$errorMsg

+
+ #end + + #if($successMsg) +
+

$successMsg

+
+ #end + + #if($redirectURLs) +
+

+ Sie werden von allen Online-Applikationen abgemeldet.
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen. +

+
+ #end + +
+
+
+ +
+ + + #foreach( $el in $redirectURLs ) + + #end + + + \ No newline at end of file diff --git a/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html b/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html new file mode 100644 index 000000000..a652855c4 --- /dev/null +++ b/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html @@ -0,0 +1,438 @@ + + + + + + + + + Single LogOut Vorgang ... + + + + + +
+
+

MOA-ID Single LogOut Information

+
+
+ + #if($errorMsg) +
+

$errorMsg

+
+ #end + + #if($successMsg) +
+

$successMsg

+
+ #end + + #if($redirectURLs) +
+

+ Sie werden von allen Online-Applikationen abgemeldet.
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen. +

+
+ #end + +
+
+
+ +
+ + + #foreach( $el in $redirectURLs ) + + #end + + + \ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java index 02e252412..a46b11c6e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java @@ -22,7 +22,15 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.moduls; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.io.StringWriter; +import java.net.URI; import java.util.List; import javax.servlet.http.Cookie; @@ -31,6 +39,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; import org.apache.velocity.app.VelocityEngine; import org.hibernate.Query; import org.hibernate.Session; @@ -53,6 +62,9 @@ import at.gv.egovernment.moa.util.MiscUtil; public class SSOManager { + private static final String HTMLTEMPLATESDIR = "htmlTemplates/"; + private static final String HTMLTEMPLATEFULL = "slo_template.html"; + private static final String SSOCOOKIE = "MOA_ID_SSO"; private static final String SSOINTERFEDERATION = "MOA_INTERFEDERATION_SSO"; @@ -274,24 +286,61 @@ public class SSOManager { } public void printSingleLogOutInfo(VelocityContext context, HttpServletResponse httpResp) throws MOAIDException { - try { + try { Logger.trace("Initialize VelocityEngine..."); VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/slo_template.html"); - - StringWriter writer = new StringWriter(); - template.merge(context, writer); - - httpResp.setContentType("text/html;charset=UTF-8"); - httpResp.getOutputStream().write(writer.toString().getBytes()); + + InputStream is = null; + try { + String rootconfigdir = AuthConfigurationProvider.getInstance().getRootConfigFileDir(); + String pathLocation = rootconfigdir + HTMLTEMPLATESDIR + HTMLTEMPLATEFULL; + File file = new File(new URI(pathLocation)); + is = new FileInputStream(file); + evaluateSLOTemplate(context, httpResp, is); + + } catch (Exception e) { + Logger.warn("SLO Template is not found in configuration directory. Load template from project library ... "); + + try { + String pathLocation = "resources/templates/" + HTMLTEMPLATEFULL; + is = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream(pathLocation); + evaluateSLOTemplate(context, httpResp, is); + + } catch (Exception e1) { + Logger.error("Single LogOut form can not created.", e); + throw new MOAIDException("Create Single LogOut information FAILED.", null, e); + } + + } finally { + if (is != null) + is.close(); + + } } catch (Exception e) { - Logger.error("Single LogOut from can not created.", e); + Logger.error("Single LogOut form can not created.", e); throw new MOAIDException("Create Single LogOut information FAILED.", null, e); } } + private void evaluateSLOTemplate(VelocityContext context, HttpServletResponse httpResp, InputStream is) throws ConfigurationException, IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(is )); + + //set default elements to velocity context + context.put("contextpath", AuthConfigurationProvider.getInstance().getPublicURLPrefix()); + + StringWriter writer = new StringWriter(); + //velocityEngine.evaluate(context, writer, "SLO_Template", reader); + Velocity.evaluate(context, writer, "SLO Template", reader); + + + httpResp.setContentType("text/html;charset=UTF-8"); + httpResp.getOutputStream().write(writer.toString().getBytes()); + + } private String getValueFromCookie(HttpServletRequest httpReq, String cookieName) { Cookie[] cookies = httpReq.getCookies(); diff --git a/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html index 16c9e87eb..a652855c4 100644 --- a/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html +++ b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html @@ -1,57 +1,438 @@ + + + + + + + + Single LogOut Vorgang ... + -