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 (limited to 'id/oa') 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