aboutsummaryrefslogtreecommitdiff
path: root/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java')
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java376
1 files changed, 173 insertions, 203 deletions
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);
-
- }
-
- }
}