diff options
Diffstat (limited to 'id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java')
-rw-r--r-- | id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java | 271 |
1 files changed, 271 insertions, 0 deletions
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; + } + +} |