diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at')
28 files changed, 1173 insertions, 428 deletions
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/builder/AuthenticationDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java index 632227d79..c0e1dd3ca 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java @@ -27,6 +27,8 @@ import iaik.x509.X509Certificate; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import javax.naming.ldap.LdapName; @@ -445,6 +447,9 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { authData.setSsoSession(true); + if (assertion.getConditions() != null && assertion.getConditions().getNotOnOrAfter() != null) + authData.setSsoSessionValidTo(assertion.getConditions().getNotOnOrAfter().toDate()); + //only for SAML1 if (PVPConstants.STORK_QAA_1_4.equals(authData.getQAALevel())) authData.setQualifiedCertificate(true); @@ -454,7 +459,7 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { } private static void buildAuthDataFormMOASession(AuthenticationData authData, AuthenticationSession session, - IOAAuthParameters oaParam) throws BuildException { + IOAAuthParameters oaParam) throws BuildException, ConfigurationException { String target = oaParam.getTarget(); @@ -465,7 +470,7 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { boolean businessService = oaParam.getBusinessService(); authData.setIssuer(session.getAuthURL()); - + //baseID or wbpk in case of BusinessService without SSO or BusinessService SSO authData.setIdentificationValue(identityLink.getIdentificationValue()); authData.setIdentificationType(identityLink.getIdentificationType()); @@ -529,6 +534,19 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { authData.setSsoSession(AuthenticationSessionStoreage.isSSOSession(session.getSessionID())); + //set max. SSO session time + if (authData.isSsoSession()) { + long maxSSOSessionTime = AuthConfigurationProvider.getInstance().getTimeOuts().getMOASessionCreated().longValue() * 1000; + Date ssoSessionValidTo = new Date(session.getSessionCreated().getTime() + maxSSOSessionTime); + authData.setSsoSessionValidTo(ssoSessionValidTo); + + } else { + //set valid to 5 min + Date ssoSessionValidTo = new Date(new Date().getTime() + 5 * 60 * 1000); + authData.setSsoSessionValidTo(ssoSessionValidTo); + + } + /* TODO: Support SSO Mandate MODE! * Insert functionality to translate mandates in case of SSO diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java index c5ba49b2e..8726c1618 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java @@ -42,6 +42,7 @@ import java.io.Serializable; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -78,6 +79,9 @@ public class AuthenticationSession implements Serializable { * session ID */ private String sessionID; + + private Date sessionCreated = null; + /** * "Geschäftsbereich" the online application belongs to; maybe <code>null</code> if the * online application is a business application @@ -344,8 +348,9 @@ public class AuthenticationSession implements Serializable { * @param id * Session ID */ - public AuthenticationSession(String id) { + public AuthenticationSession(String id, Date created) { sessionID = id; + sessionCreated = created; // setTimestampStart(); // infoboxValidators = new ArrayList(); } @@ -1050,6 +1055,13 @@ public class AuthenticationSession implements Serializable { this.storkAuthnResponse = storkAuthnResponse; } + /** + * @return the sessionCreated + */ + public Date getSessionCreated() { + return sessionCreated; + } + 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/AuthenticationData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java index 33e62d3d0..5685977bc 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java @@ -135,6 +135,7 @@ public class AuthenticationData implements IAuthData, Serializable { private String QAALevel = null; private boolean ssoSession = false; + private Date ssoSessionValidTo = null; private boolean interfederatedSSOSession = false; private String interfederatedIDP = null; @@ -656,7 +657,23 @@ public class AuthenticationData implements IAuthData, Serializable { public void setInterfederatedIDP(String interfederatedIDP) { this.interfederatedIDP = interfederatedIDP; } + + /** + * @return the ssoSessionValidTo + */ + public Date getSsoSessionValidTo() { + return ssoSessionValidTo; + } + + /** + * @param ssoSessionValidTo the ssoSessionValidTo to set + */ + public void setSsoSessionValidTo(Date ssoSessionValidTo) { + this.ssoSessionValidTo = ssoSessionValidTo; + } + + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java index 4ea81f134..7e421da0f 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java @@ -53,6 +53,8 @@ public interface IAuthData { String getBPK(); String getBPKType(); + Date getSsoSessionValidTo(); + String getInterfederatedIDP(); String getIdentificationValue(); 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..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,13 +24,18 @@ 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; 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,58 +57,93 @@ public class SLOInformationContainer implements Serializable { public void parseActiveOAs(List<OASessionStore> dbOAs, String removeOAID) { - activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>(); - activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>(); + if (activeBackChannelOAs == null) + activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>(); + if (activeFrontChannalOAs == null) + activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>(); 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<InterfederationSessionStore> dbIDPs, + String removeIDP) { + if (activeBackChannelOAs == null) + activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>(); + if (activeFrontChannalOAs == null) + activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>(); + + if (dbIDPs != null) { + for (InterfederationSessionStore el : dbIDPs) { + if (!el.getIdpurlprefix().equals(removeIDP)) { + SingleLogoutService sloDesc; try { - sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(oa.getOaurlprefix()); + sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(el.getIdpurlprefix()); - 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(), + 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<String> 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<Entry<String, SLOInformationImpl>> getFrontChannelOASessionDescriptions() { + return activeFrontChannalOAs.entrySet(); } public void removeFrontChannelOA(String oaID) { @@ -147,9 +187,5 @@ public class SLOInformationContainer implements Serializable { if (sloFailedOAs == null) sloFailedOAs = new ArrayList<String>(); sloFailedOAs.add(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..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 @@ -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<OASessionStore> dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); + List<InterfederationSessionStore> 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<String> nextOAInterator = sloContainer.getNextBackChannelOA(); + while (nextOAInterator.hasNext()) { + SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next()); + LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); + + try { + List<XMLObject> 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<Entry<String, SLOInformationImpl>> sloDescr = sloContainer.getFrontChannelOASessionDescriptions(); + List<String> sloReqList = new ArrayList<String>(); + for (Entry<String, SLOInformationImpl> 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"); @@ -196,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()); 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..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,17 +22,31 @@ *******************************************************************************/ 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; 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.Velocity; +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,11 +56,15 @@ 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; 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"; @@ -267,6 +285,63 @@ public class SSOManager { } + public void printSingleLogOutInfo(VelocityContext context, HttpServletResponse httpResp) throws MOAIDException { + try { + Logger.trace("Initialize VelocityEngine..."); + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + + 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 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/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/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java index 01f7e18ba..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); @@ -265,14 +265,14 @@ public class MetadataAction implements IAction { // 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 redirectSLOService = + SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectSLOService.setLocation(PVPConfiguration + .getInstance().getSPSSORedirectService()); + redirectSLOService + .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); @@ -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/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<IDecoder> decoder = new ArrayList<IDecoder>(); private static HashMap<String, IAction> actions = new HashMap<String, IAction>(); @@ -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/SingleLogOutAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java index c67d10ab7..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,51 @@ */ 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; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; @@ -49,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; @@ -59,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 @@ -82,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 " @@ -104,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 { @@ -116,101 +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<OASessionStore> dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); - SLOInformationContainer sloContainer = new SLOInformationContainer(); - sloContainer.setSloRequest(pvpReq); - 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<String> nextOAInterator = sloContainer.getNextBackChannelOA(); - while (nextOAInterator.hasNext()) { - SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next()); - LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); - - try { - List<XMLObject> 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 { @@ -218,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; } @@ -245,117 +320,12 @@ public class SingleLogOutAction implements IAction { return PVP2XProtocol.SINGLELOGOUT; } - private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { - Status status = logOutResp.getStatus(); - if (!status.getStatusCode().equals(StatusCode.SUCCESS_URI)) { - Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() - + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() - + " Message: " + status.getStatusMessage().getMessage() + ")"); - 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/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<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); 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<SAMLObject, ?, ?> messageContext = 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..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,30 +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; @@ -56,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<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + 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<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + 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); @@ -75,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); @@ -94,14 +244,8 @@ public class SingleLogOutBuilder { return sloResp; } - public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> 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<String> failedOAs) throws MOAIDException { + LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); Status status; if (failedOAs == null || failedOAs.size() == 0) { @@ -122,10 +266,41 @@ 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); - SPSSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + SSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); SingleLogoutService sloService = null; for (SingleLogoutService el : spsso.getSingleLogoutServices()) { @@ -139,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; @@ -173,14 +348,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/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java index 4d6343fce..fa5d252bd 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java @@ -135,7 +135,8 @@ public class PVP2AssertionBuilder implements PVPConstants { SubjectConfirmationData subjectConfirmationData = null; return buildGenericAssertion(attrQuery.getIssuer().getValue(), date, - authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex); + authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, + new DateTime(authData.getSsoSessionValidTo().getTime())); } public static Assertion buildAssertion(AuthnRequest authnRequest, @@ -393,8 +394,8 @@ public class PVP2AssertionBuilder implements PVPConstants { SubjectConfirmationData subjectConfirmationData = SAML2Utils .createSAMLObject(SubjectConfirmationData.class); subjectConfirmationData.setInResponseTo(authnRequest.getID()); - subjectConfirmationData.setNotOnOrAfter(date.plusMinutes(5)); - + subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); + subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); //set SLO information @@ -402,13 +403,13 @@ public class PVP2AssertionBuilder implements PVPConstants { sloInformation.setNameIDFormat(subjectNameID.getFormat()); sloInformation.setSessionIndex(sessionIndex); - return buildGenericAssertion(peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex); + return buildGenericAssertion(peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); } private static Assertion buildGenericAssertion(String entityID, DateTime date, AuthnContextClassRef authnContextClassRef, List<Attribute> attrList, NameID subjectNameID, SubjectConfirmationData subjectConfirmationData, - String sessionIndex) throws ConfigurationException { + String sessionIndex, DateTime isValidTo) throws ConfigurationException { Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class); AuthnContext authnContext = SAML2Utils @@ -448,10 +449,9 @@ public class PVP2AssertionBuilder implements PVPConstants { audience.setAudienceURI(entityID); audienceRestriction.getAudiences().add(audience); - conditions.setNotBefore(date); - - conditions.setNotOnOrAfter(date.plusMinutes(5)); - + conditions.setNotBefore(date); + conditions.setNotOnOrAfter(isValidTo); + conditions.getAudienceRestrictions().add(audienceRestriction); assertion.setConditions(conditions); 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; } 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<Assertion> 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/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..1c74aea55 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) { @@ -72,19 +72,20 @@ public class AuthenticationSessionStoreage { } } - public static AuthenticationSession createSession() throws MOADatabaseException { + public static AuthenticationSession createSession() throws MOADatabaseException, BuildException { String id = Random.nextRandom(); - AuthenticationSession session = new AuthenticationSession(id); - + AuthenticatedSessionStore dbsession = new AuthenticatedSessionStore(); dbsession.setSessionid(id); dbsession.setAuthenticated(false); - //set Timestamp in this state, because automated timestamp generation is buggy in Hibernate 4.2.1 - dbsession.setCreated(new Date()); - dbsession.setUpdated(new Date()); + //set Timestamp in this state, because automated timestamp generation is buggy in Hibernate 4.2.1 + Date now = new Date(); + dbsession.setCreated(now); + dbsession.setUpdated(now); - dbsession.setSession(SerializationUtils.serialize(session)); + AuthenticationSession session = new AuthenticationSession(id, now); + encryptSession(session, dbsession); //store AssertionStore element to Database try { @@ -102,7 +103,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 +123,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 +176,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 +208,7 @@ public class AuthenticationSessionStoreage { AuthenticatedSessionStore session; try { - session = searchInDatabase(moaSessionID); + session = searchInDatabase(moaSessionID, true); session.setAuthenticated(value); MOASessionDBUtils.saveOrUpdate(session); @@ -249,7 +250,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 +392,36 @@ public class AuthenticationSessionStoreage { MiscUtil.assertNotNull(moaSession, "MOASession"); try { - AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID()); - return dbsession.getActiveOAsessions(); + List<OASessionStore> oas = new ArrayList<OASessionStore>(); + + 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<InterfederationSessionStore> getAllActiveIDPsFromMOASession(AuthenticationSession moaSession) { + MiscUtil.assertNotNull(moaSession, "MOASession"); + + try { + List<InterfederationSessionStore> idps = new ArrayList<InterfederationSessionStore>(); + 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 +504,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) { @@ -646,7 +675,7 @@ public class AuthenticationSessionStoreage { return result.get(0).getInderfederation().get(0); } - public static String createInterfederatedSession(IRequest req, boolean isAuthenticated, String ssoID) throws MOADatabaseException, AssertionAttributeExtractorExeption { + public static String createInterfederatedSession(IRequest req, boolean isAuthenticated, String ssoID) throws MOADatabaseException, AssertionAttributeExtractorExeption, BuildException { AuthenticatedSessionStore dbsession = null; //search for active SSO session @@ -654,7 +683,7 @@ public class AuthenticationSessionStoreage { String moaSession = getMOASessionSSOID(ssoID); if (MiscUtil.isNotEmpty(moaSession)) { try { - dbsession = searchInDatabase(moaSession); + dbsession = searchInDatabase(moaSession, true); }catch (MOADatabaseException e) { @@ -664,28 +693,28 @@ public class AuthenticationSessionStoreage { String id = null; Date now = new Date(); - //create new MOASession if any exists + AuthenticationSession session = null; if (dbsession == null) { id = Random.nextRandom(); dbsession = new AuthenticatedSessionStore(); dbsession.setSessionid(id); dbsession.setCreated(now); - + session = new AuthenticationSession(id, now); + } else { id = dbsession.getSessionid(); - + session = decryptSession(dbsession); + } - + dbsession.setInterfederatedSSOSession(true); dbsession.setAuthenticated(isAuthenticated); - dbsession.setUpdated(now); - - AuthenticationSession session = new AuthenticationSession(id); + dbsession.setUpdated(now); session.setAuthenticated(true); - session.setAuthenticatedUsed(false); - dbsession.setSession(SerializationUtils.serialize(session)); - + session.setAuthenticatedUsed(false); + encryptSession(session, dbsession); + //add interfederation information List<InterfederationSessionStore> idpList = dbsession.getInderfederation(); InterfederationSessionStore idp = null; @@ -889,7 +918,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 +932,8 @@ public class AuthenticationSessionStoreage { result = query.list(); //send transaction - session.getTransaction().commit(); + if (commit) + session.getTransaction().commit(); } Logger.trace("Found entries: " + result.size()); |