diff options
author | Andreas Fitzek <andreas.fitzek@iaik.tugraz.at> | 2013-05-02 13:35:38 +0200 |
---|---|---|
committer | Andreas Fitzek <andreas.fitzek@iaik.tugraz.at> | 2013-05-02 13:35:38 +0200 |
commit | 36a3ddc4e108efc7813b655b74e9919c00c9fd94 (patch) | |
tree | 9208ea261f96c9cd276d3b1b1571b9ec33a28009 /id | |
parent | 8de3af116a8f306a6a7690e6c6f0c9b0e88b9c67 (diff) | |
download | moa-id-spss-36a3ddc4e108efc7813b655b74e9919c00c9fd94.tar.gz moa-id-spss-36a3ddc4e108efc7813b655b74e9919c00c9fd94.tar.bz2 moa-id-spss-36a3ddc4e108efc7813b655b74e9919c00c9fd94.zip |
PVP2 basic authnrequest handling and assertion building
Diffstat (limited to 'id')
38 files changed, 1408 insertions, 137 deletions
diff --git a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml index 1d75053f2..032f06911 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml @@ -22,20 +22,20 @@ <!-- Legacy Rules --> <rule match-type="regex"> <from>^/StartAuthentication$</from> - <to type="forward">/AuthDispatcher?mod=id_saml1&action=GetArtifact</to> + <to type="forward">/dispatcher?mod=id_saml1&action=GetArtifact</to> </rule> <rule match-type="regex"> <from>^/StartAuthentication\?(.*)$</from> - <to type="forward">/AuthDispatcher?mod=id_saml1&action=GetArtifact&$1</to> + <to type="forward">/dispatcher?mod=id_saml1&action=GetArtifact&$1</to> </rule> <rule match-type="regex"> <from>^/auth/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)$</from> - <to type="forward">/AuthDispatcher?mod=$1&action=$2</to> + <to type="forward">/dispatcher?mod=$1&action=$2</to> </rule> <rule match-type="regex"> <from>^/auth/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)\?(.*)$</from> - <to type="forward">/AuthDispatcher?mod=$1&action=$2&$3</to> + <to type="forward">/dispatcher?mod=$1&action=$2&$3</to> </rule> diff --git a/id/server/auth/src/main/webapp/WEB-INF/web.xml b/id/server/auth/src/main/webapp/WEB-INF/web.xml index dcacce819..f2235b91f 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/web.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/web.xml @@ -80,16 +80,16 @@ at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet</servlet-class> </servlet> - <!-- Dispatcher servlets --> + <!-- Dispatcher servlets <servlet> <servlet-name>AuthDispatcherServlet</servlet-name> <display-name>AuthDispatcher Servlet</display-name> <servlet-class>at.gv.egovernment.moa.id.entrypoints.AuthDispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> - </servlet> + </servlet>--> <servlet> - <servlet-name>UnauthDispatcherServlet</servlet-name> - <display-name>UnauthDispatcher Servlet</display-name> + <servlet-name>DispatcherServlet</servlet-name> + <display-name>Dispatcher Servlet</display-name> <servlet-class>at.gv.egovernment.moa.id.entrypoints.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> @@ -104,13 +104,13 @@ <servlet-mapping> - <servlet-name>UnauthDispatcherServlet</servlet-name> - <url-pattern>/UnauthDispatcher</url-pattern> + <servlet-name>DispatcherServlet</servlet-name> + <url-pattern>/dispatcher</url-pattern> </servlet-mapping> - <servlet-mapping> + <!-- servlet-mapping> <servlet-name>AuthDispatcherServlet</servlet-name> <url-pattern>/AuthDispatcher</url-pattern> - </servlet-mapping> + </servlet-mapping --> <!-- servlet mapping for jsp pages --> @@ -183,8 +183,6 @@ <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern> - <dispatcher>REQUEST</dispatcher> - <dispatcher>FORWARD</dispatcher> </filter-mapping> <!-- <filter-mapping> <filter-name>DispatcherDecoratorFilter</filter-name> <url-pattern>/AuthDispatcher</url-pattern> <dispatcher>REQUEST</dispatcher> diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml index 7fbde1c6a..1244d4bd6 100644 --- a/id/server/idserverlib/pom.xml +++ b/id/server/idserverlib/pom.xml @@ -114,6 +114,11 @@ <artifactId>iaik_X509TrustManager</artifactId>
</dependency>
<dependency>
+ <groupId>edu.internet2.middleware</groupId>
+ <artifactId>shibboleth-common</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ <dependency>
<groupId>regexp</groupId>
<artifactId>regexp</artifactId>
</dependency>
@@ -135,7 +140,7 @@ <groupId>MOA.id</groupId>
<artifactId>stork-saml-engine</artifactId>
<version>1.5.2</version>
- </dependency>
+ </dependency>
</dependencies>
<build>
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java index 57c14b15e..afd25dcad 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java @@ -27,7 +27,6 @@ import iaik.pki.PKIException; import iaik.x509.X509Certificate; import java.io.ByteArrayInputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; @@ -66,7 +65,6 @@ import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.ParseException; import at.gv.egovernment.moa.id.ServiceException; import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; -import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataAssertionBuilder; import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; import at.gv.egovernment.moa.id.auth.builder.CertInfoVerifyXMLSignatureRequestBuilder; import at.gv.egovernment.moa.id.auth.builder.CreateXMLSignatureRequestBuilder; @@ -75,7 +73,6 @@ import at.gv.egovernment.moa.id.auth.builder.GetIdentityLinkFormBuilder; import at.gv.egovernment.moa.id.auth.builder.InfoboxReadRequestBuilder; import at.gv.egovernment.moa.id.auth.builder.InfoboxValidatorParamsBuilder; import at.gv.egovernment.moa.id.auth.builder.PersonDataBuilder; -import at.gv.egovernment.moa.id.auth.builder.SAMLArtifactBuilder; import at.gv.egovernment.moa.id.auth.builder.SelectBKUFormBuilder; import at.gv.egovernment.moa.id.auth.builder.VerifyXMLSignatureRequestBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; @@ -95,7 +92,6 @@ import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; import at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet; import at.gv.egovernment.moa.id.auth.stork.STORKAuthnRequestProcessor; -import at.gv.egovernment.moa.id.auth.stork.STORKException; import at.gv.egovernment.moa.id.auth.validator.CreateXMLSignatureResponseValidator; import at.gv.egovernment.moa.id.auth.validator.IdentityLinkValidator; import at.gv.egovernment.moa.id.auth.validator.InfoboxValidator; @@ -2871,15 +2867,17 @@ public class AuthenticationServer implements MOAIDAuthConstants { String issuerValue = HTTPUtils.getBaseURL(req); Logger.debug("Issuer value: " + issuerValue); - QualityAuthenticationAssuranceLevel qaaLevel = STORKMessagesBuilder.buildQualityAuthenticationAssuranceLevel(oaParam.getQaaLevel().getValue()); + + QualityAuthenticationAssuranceLevel qaaLevel = null;//TODO UNCOMMENT AGAIN !! = STORKMessagesBuilder.buildQualityAuthenticationAssuranceLevel(oaParam.getQaaLevel().getValue()); Logger.debug("QAALevel: " + qaaLevel.getValue()); - RequestedAttributes requestedAttributes; + RequestedAttributes requestedAttributes = null; - requestedAttributes = oaParam.getRequestedAttributes(); + //TODO UNCOMMENT AGAIN !! requestedAttributes = oaParam.getRequestedAttributes(); requestedAttributes.detach(); List<RequestedAttribute> reqAttributeList = new ArrayList<RequestedAttribute>(); - List<RequestedAttribute> oaReqAttributeList = new ArrayList<RequestedAttribute>(oaParam.getRequestedAttributes().getRequestedAttributes()); + List<RequestedAttribute> oaReqAttributeList = null; + //TODO UNCOMMENT AGAIN !! oaReqAttributeList = new ArrayList<RequestedAttribute>(oaParam.getRequestedAttributes().getRequestedAttributes()); //check if country specific attributes must be additionally requested if (!cpeps.getCountrySpecificRequestedAttributes().isEmpty()) { //add country specific attributes to be requested (Hierarchy: default oa attributes > country specific attributes > oa specific attributes diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java index 2133d0455..54d96ee2e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java @@ -116,7 +116,7 @@ public class StartAuthenticationServlet extends AuthServlet { String modul = request.requestedModule();//req.getParameter(PARAM_MODUL); String action = request.requestedAction();//req.getParameter(PARAM_ACTION); - + request.getOAURL(); // escape parameter strings //TODO: use URLEncoder.encode!! target = StringEscapeUtils.escapeHtml(target); @@ -130,6 +130,8 @@ public class StartAuthenticationServlet extends AuthServlet { modul = StringEscapeUtils.escapeHtml(modul); action = StringEscapeUtils.escapeHtml(action); + oaURL = request.getOAURL(); + setNoCachingHeadersInHttpRespone(req, resp); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/ConfigurationBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/ConfigurationBuilder.java index 839de48bf..2f138fbfc 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/ConfigurationBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/ConfigurationBuilder.java @@ -704,28 +704,28 @@ public List getTrustedTemplateURLs() { } //add STORK Configuration specific to OA (RequestedAttributes, QAALevel) - QualityAuthenticationAssuranceLevel qaaLevel = buildOaSTORKQAALevel(authComponent); - if (qaaLevel != null) { - oap.setQaaLevel(qaaLevel); - Logger.debug("Using non-MOA-default STORK QAALevel for this OA " + "(" + oap.getPublicURLPrefix() + "): " + qaaLevel.getValue()); - } - - RequestedAttributes additionalRequestedAttributes = buildOaSTORKRequestedAttributes(authComponent); + //QualityAuthenticationAssuranceLevel qaaLevel = buildOaSTORKQAALevel(authComponent); + //if (qaaLevel != null) { + // oap.setQaaLevel(qaaLevel); + // Logger.debug("Using non-MOA-default STORK QAALevel for this OA " + "(" + oap.getPublicURLPrefix() + "): " + qaaLevel.getValue()); + //} - if(!additionalRequestedAttributes.getRequestedAttributes().isEmpty()) { - //we have additional STORK attributes to request for this OA - Logger.debug("Using non-MOA-default STORK RequestedAttributes for this OA " + "(" + oap.getPublicURLPrefix() + "): "); - for (RequestedAttribute addReqAttr : additionalRequestedAttributes.getRequestedAttributes()) { - if (!SAMLUtil.containsAttribute(oap.getRequestedAttributes().getRequestedAttributes(),addReqAttr.getName())) { - addReqAttr.detach(); - oap.getRequestedAttributes().getRequestedAttributes().add(addReqAttr); - Logger.debug("Requesting additional attribute: " + addReqAttr.getName() + ", isRequired: " + addReqAttr.isRequired()); - } - } + //RequestedAttributes additionalRequestedAttributes = buildOaSTORKRequestedAttributes(authComponent); + // + //if(!additionalRequestedAttributes.getRequestedAttributes().isEmpty()) { + // //we have additional STORK attributes to request for this OA + // Logger.debug("Using non-MOA-default STORK RequestedAttributes for this OA " + "(" + oap.getPublicURLPrefix() + "): "); + // for (RequestedAttribute addReqAttr : additionalRequestedAttributes.getRequestedAttributes()) { + // if (!SAMLUtil.containsAttribute(oap.getRequestedAttributes().getRequestedAttributes(),addReqAttr.getName())) { + /// addReqAttr.detach(); + // oap.getRequestedAttributes().getRequestedAttributes().add(addReqAttr); + // Logger.debug("Requesting additional attribute: " + addReqAttr.getName() + ", isRequired: " + addReqAttr.isRequired()); + // } + // } - } else { - //do nothing, only request default attributes - } + //} else { + // //do nothing, only request default attributes + //} } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameter.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameter.java index 091a01bf7..10dd2cfea 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameter.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameter.java @@ -133,17 +133,17 @@ public class OAAuthParameter extends OAParameter { /** * STORK QAA Level, Default = 4 */ - private QualityAuthenticationAssuranceLevel qaaLevel = STORKMessagesBuilder.buildQualityAuthenticationAssuranceLevel(4); + // private QualityAuthenticationAssuranceLevel qaaLevel = STORKMessagesBuilder.buildQualityAuthenticationAssuranceLevel(4); /** * STORK RequestedAttributes for Online Application * Default RequestedAttributes are: eIdentifier, givenName, surname, dateOfBirth */ - private RequestedAttributes requestedAttributes = STORKMessagesBuilder.buildRequestedAttributes( - STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_EIDENTIFIER, true, null), - STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_GIVENNAME, true, null), - STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_SURNAME, true, null), - STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_DATEOFBIRTH, false, null)); + //private RequestedAttributes requestedAttributes = STORKMessagesBuilder.buildRequestedAttributes( +// STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_EIDENTIFIER, true, null), +// STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_GIVENNAME, true, null), +// STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_SURNAME, true, null), +// STORKMessagesBuilder.buildRequestedAttribute(STORKConstants.STORK_ATTRIBUTE_DATEOFBIRTH, false, null)); /** @@ -469,33 +469,33 @@ public class OAAuthParameter extends OAParameter { * Returns the defined STORK QAALevel * @return STORK QAALevel */ - public QualityAuthenticationAssuranceLevel getQaaLevel() { + /*public QualityAuthenticationAssuranceLevel getQaaLevel() { return qaaLevel; - } + }*/ /** * Sets the STORK QAALevel * @param qaaLevel */ - public void setQaaLevel(QualityAuthenticationAssuranceLevel qaaLevel) { + /*public void setQaaLevel(QualityAuthenticationAssuranceLevel qaaLevel) { this.qaaLevel = qaaLevel; - } + }*/ /** * Returns the desired STORK Requested Attributes * @return STORK Requested Attributes */ - public RequestedAttributes getRequestedAttributes() { - return requestedAttributes; - } + //public RequestedAttributes getRequestedAttributes() { + // return requestedAttributes; + //} /** * Sets the desired STORK Requested Attributes * @param requestedAttributes */ - public void setRequestedAttributes(RequestedAttributes requestedAttributes) { - this.requestedAttributes = requestedAttributes; - } + //public void setRequestedAttributes(RequestedAttributes requestedAttributes) { + // this.requestedAttributes = requestedAttributes; + //} 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 72ade4f25..27cd2b5a5 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 @@ -1,6 +1,7 @@ package at.gv.egovernment.moa.id.entrypoints; import java.io.IOException; +import java.util.Iterator; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -142,18 +143,39 @@ public class DispatcherServlet extends AuthServlet { IModulInfo info = ModulStorage.getModuleByPath(module); + IAction moduleAction = null; + if (info == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND); - Logger.error("Protocol " + module + " has no module registered"); - return; - } - IAction moduleAction = info.getAction(action); + Iterator<IModulInfo> modules = ModulStorage.getAllModules() + .iterator(); + while (modules.hasNext()) { + info = modules.next(); + moduleAction = info.canHandleRequest(req, resp); + if (moduleAction != null) { + action = moduleAction.getDefaultActionName(); + module = info.getPath(); + break; + } + info = null; + } + + if (moduleAction == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + Logger.error("Protocol " + module + + " has no module registered"); + return; + } + } if (moduleAction == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND); - Logger.error("Action " + action + " is not available!"); - return; + moduleAction = info.getAction(action); + + if (moduleAction == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + Logger.error("Action " + action + " is not available!"); + return; + } } HttpSession httpSession = req.getSession(); @@ -175,7 +197,7 @@ public class DispatcherServlet extends AuthServlet { if (protocolRequest == null) { protocolRequest = info.preProcess(req, resp, action); - if(protocolRequest != null) { + if (protocolRequest != null) { protocolRequest.setAction(action); protocolRequest.setModule(module); } @@ -188,7 +210,7 @@ public class DispatcherServlet extends AuthServlet { } RequestStorage.setPendingRequest(httpSession, protocolRequest); - + if (moduleAction.needAuthentication(protocolRequest, req, resp)) { if (protocolRequest.isPassiv() && protocolRequest.forceAuth()) { @@ -230,7 +252,7 @@ public class DispatcherServlet extends AuthServlet { moduleAction.processRequest(protocolRequest, req, resp); RequestStorage.removePendingRequest(httpSession); - + } catch (Throwable e) { // Try handle module specific, if not possible rethrow if (!info.generateErrorMessage(e, req, resp)) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IAction.java index 10f3ff696..6630693a6 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IAction.java @@ -3,9 +3,13 @@ package at.gv.egovernment.moa.id.moduls; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; public interface IAction extends MOAIDAuthConstants { - public void processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp); + public void processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) + throws MOAIDException; public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp); + + public String getDefaultActionName(); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IModulInfo.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IModulInfo.java index 0098ec5af..181955c2a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IModulInfo.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/IModulInfo.java @@ -1,7 +1,5 @@ package at.gv.egovernment.moa.id.moduls; -import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -18,5 +16,8 @@ public interface IModulInfo { HttpServletResponse response, String action) throws MOAIDException; + public IAction canHandleRequest(HttpServletRequest request, + HttpServletResponse response); + public boolean generateErrorMessage(Throwable e,HttpServletRequest request, HttpServletResponse response); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AuthenticationAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AuthenticationAction.java index efdfd9c47..17f1b631b 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AuthenticationAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AuthenticationAction.java @@ -3,14 +3,18 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler.RequestManager; public class AuthenticationAction implements IAction { public void processRequest(IRequest req, HttpServletRequest httpReq, - HttpServletResponse httpResp) { + HttpServletResponse httpResp) throws MOAIDException { System.out.println("Process PVP2 auth request!"); + PVPTargetConfiguration pvpRequest = (PVPTargetConfiguration) req; + RequestManager.getInstance().handle(pvpRequest.request, httpReq, httpResp); } public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, @@ -18,4 +22,8 @@ public class AuthenticationAction implements IAction { return true; } + public String getDefaultActionName() { + return (PVP2XProtocol.REDIRECT); + } + } 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 fa5ff9ecf..847f1ae54 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 @@ -11,6 +11,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.Status; @@ -27,9 +29,15 @@ import at.gv.egovernment.moa.id.moduls.NoPassivAuthenticationException; import at.gv.egovernment.moa.id.moduls.ServletInfo; import at.gv.egovernment.moa.id.moduls.ServletType; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IDecoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOAResponse; 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.utils.SAML2Utils; +import at.gv.egovernment.moa.id.protocols.pvp2x.validation.ChainSAMLValidator; +import at.gv.egovernment.moa.id.protocols.pvp2x.validation.SAMLSignatureValidator; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.ChainSAMLVerifier; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.SAMLVerifierMOASP; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { @@ -46,6 +54,10 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { private static HashMap<String, IAction> actions = new HashMap<String, IAction>(); + private ChainSAMLVerifier samlVerifier = new ChainSAMLVerifier(); + + private ChainSAMLValidator samlValidator = new ChainSAMLValidator(); + static { servletList.add(new ServletInfo(PVPProcessor.class, REDIRECT, ServletType.AUTH)); @@ -94,6 +106,14 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return null; } + public PVP2XProtocol() { + super(); + + samlVerifier.addVerifier(new SAMLVerifierMOASP()); + + samlValidator.addValidator(new SAMLSignatureValidator()); + } + public IRequest preProcess(HttpServletRequest request, HttpServletResponse response, String action) throws MOAIDException { @@ -104,15 +124,46 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { try { PVPTargetConfiguration config = new PVPTargetConfiguration(); - RequestAbstractType samlReq = decoder.decodeRequest(request, response); - - String oaURL = (String) request.getParameter(PARAM_OA); + MOARequest moaRequest = decoder.decodeRequest(request, response); + + RequestAbstractType samlReq = moaRequest.getSamlRequest(); + + //String xml = PrettyPrinter.prettyPrint(SAML2Utils.asDOMDocument(samlReq)); + + //Logger.info("SAML : " + xml); + + // TODO: verify samlReq + //samlValidator.validateRequest(samlReq); + + // TODO: validate samlReq for + //samlVerifier.verifyRequest(samlReq); + + // TODO: OAURL is AssertionConsumerService URL from entitydescriptor ... + + if(!(samlReq instanceof AuthnRequest)) { + throw new MOAIDException("Unsupported request", new Object[] {}); + } + + AuthnRequest authnRequest = (AuthnRequest)samlReq; + + Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); + int idx = 0; + + if(aIdx != null) { + idx = aIdx.intValue(); + } + + String oaURL = moaRequest.getEntityMetadata(). + getSPSSODescriptor(SAMLConstants.SAML20P_NS). + getAssertionConsumerServices().get(idx).getLocation(); + + //String oaURL = (String) request.getParameter(PARAM_OA); oaURL = StringEscapeUtils.escapeHtml(oaURL); if (!ParamValidatorUtils.isValidOA(oaURL)) throw new WrongParametersException("StartAuthentication", PARAM_OA, "auth.12"); config.setOAURL(oaURL); - config.setRequest(samlReq); + config.setRequest(moaRequest); request.getSession().setAttribute(PARAM_OA, oaURL); return config; @@ -146,4 +197,12 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return actions.get(action); } + public IAction canHandleRequest(HttpServletRequest request, + HttpServletResponse response) { + if(request.getParameter("SAMLRequest") != null) { + return getAction(REDIRECT); + } + return null; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java index 4f4dedc76..f19602c1e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java @@ -3,15 +3,16 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; import org.opensaml.saml2.core.RequestAbstractType; import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; public class PVPTargetConfiguration extends RequestImpl { - RequestAbstractType request; + MOARequest request; - public RequestAbstractType getRequest() { + public MOARequest getRequest() { return request; } - public void setRequest(RequestAbstractType request) { + public void setRequest(MOARequest request) { this.request = request; } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSignedException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSignedException.java new file mode 100644 index 000000000..40f5685ad --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSignedException.java @@ -0,0 +1,17 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x; + +import at.gv.egovernment.moa.id.MOAIDException; + +public class SAMLRequestNotSignedException extends MOAIDException { + + public SAMLRequestNotSignedException(String messageId, Object[] parameters) { + super(messageId, parameters); + // TODO Auto-generated constructor stub + } + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSupported.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSupported.java index 3a71495c1..16b388a09 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSupported.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SAMLRequestNotSupported.java @@ -1,6 +1,12 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; -public class SAMLRequestNotSupported extends Exception { +import at.gv.egovernment.moa.id.MOAIDException; + +public class SAMLRequestNotSupported extends MOAIDException { + + public SAMLRequestNotSupported(String messageId, Object[] parameters) { + super(messageId, parameters); + } /** * 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 0e7dd3377..8e27de7a5 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 @@ -9,11 +9,11 @@ import org.opensaml.ws.message.decoder.MessageDecodingException; import org.opensaml.xml.security.SecurityException; public interface IDecoder { - public RequestAbstractType decodeRequest(HttpServletRequest req, + public MOARequest decodeRequest(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException; - public Response decodeRespone(HttpServletRequest req, + public MOAResponse decodeRespone(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IEncoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IEncoder.java index 8df44c270..f2c392a2a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IEncoder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IEncoder.java @@ -4,16 +4,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.opensaml.saml2.core.RequestAbstractType; -import org.opensaml.saml2.core.Response; -import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.xml.security.SecurityException; public interface IEncoder { public void encodeRequest(HttpServletRequest req, - HttpServletResponse resp, RequestAbstractType request) - throws MessageDecodingException, SecurityException; + HttpServletResponse resp, RequestAbstractType request, String targetLocation) + throws MessageEncodingException, SecurityException; public void encodeRespone(HttpServletRequest req, - HttpServletResponse resp, Response response) - throws MessageDecodingException, SecurityException; + HttpServletResponse resp, StatusResponseType response, String targetLocation) + throws MessageEncodingException, SecurityException; } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOARequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOARequest.java new file mode 100644 index 000000000..946f62066 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOARequest.java @@ -0,0 +1,40 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.binding; + +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.metadata.EntityDescriptor; + +public class MOARequest { + private RequestAbstractType samlRequest; + private EntityDescriptor entityMetadata; + private boolean verified = false; + + public MOARequest(RequestAbstractType request) { + samlRequest = request; + } + + public RequestAbstractType getSamlRequest() { + return samlRequest; + } + + public void setSamlRequest(RequestAbstractType request) { + this.samlRequest = request; + } + + public boolean isVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } + + public EntityDescriptor getEntityMetadata() { + return entityMetadata; + } + + public void setEntityMetadata(EntityDescriptor entityMetadata) { + this.entityMetadata = entityMetadata; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOAResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOAResponse.java new file mode 100644 index 000000000..47f935b0c --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/MOAResponse.java @@ -0,0 +1,38 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.binding; + +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.metadata.EntityDescriptor; + +public class MOAResponse { + private Response samlResponse; + private EntityDescriptor entityMetadata; + private boolean verified = false; + + public MOAResponse(Response response) { + samlResponse = response; + } + + public Response getSamlResponse() { + return samlResponse; + } + + public void setSamlResponse(Response samlResponse) { + this.samlResponse = samlResponse; + } + + public boolean isVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } + + public EntityDescriptor getEntityMetadata() { + return entityMetadata; + } + + public void setEntityMetadata(EntityDescriptor entityMetadata) { + this.entityMetadata = entityMetadata; + } +} 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 cb0f0f8d8..06ce311cf 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 @@ -1,40 +1,134 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.binding; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; +import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.opensaml.xml.parse.BasicParserPool; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; public class PostBinding implements IDecoder, IEncoder { public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request) throws MessageDecodingException, + RequestAbstractType request, String targetLocation) throws MessageEncodingException, SecurityException{ // TODO Auto-generated method stub } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - Response response) throws MessageDecodingException, + StatusResponseType response, String targetLocation) throws MessageEncodingException, SecurityException{ - // TODO Auto-generated method stub - + KeyStore keyStore; + + try { + keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + + FileInputStream inputStream = new FileInputStream( + "/home/afitzek/server/moaid_conf/moaid/pvp.ks"); + keyStore.load(inputStream, "123456".toCharArray()); + inputStream.close(); + + BasicCredential credentials = new BasicCredential(); + PrivateKey key = (PrivateKey) keyStore.getKey("pvpIDP", + "123456".toCharArray()); + Certificate cert = keyStore.getCertificate("pvpIDP"); + credentials.setPublicKey(cert.getPublicKey()); + credentials.setPrivateKey(key); + credentials.setUsageType(UsageType.SIGNING); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(credentials); + + response.setSignature(signer); + + VelocityEngine engine = new VelocityEngine(); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); + engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + engine.setProperty("classpath.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + engine.init(); + + HTTPPostEncoder encoder = new HTTPPostEncoder(engine, + "resources/templates/pvp_postbinding_template.html"); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + resp, true); + BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-REDIRECT"); + service.setLocation(targetLocation); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + // context.setOutboundMessage(authReq); + context.setOutboundSAMLMessage(response); + context.setOutboundMessageTransport(responseAdapter); + + encoder.encode(context); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (UnrecoverableKeyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } - public RequestAbstractType decodeRequest(HttpServletRequest req, + public MOARequest decodeRequest(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException{ + + HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); BasicSAMLMessageContext<RequestAbstractType, ?, ?> messageContext = new BasicSAMLMessageContext<RequestAbstractType, SAMLObject, SAMLObject>(); @@ -45,11 +139,14 @@ public class PostBinding implements IDecoder, IEncoder { RequestAbstractType inboundMessage = (RequestAbstractType) messageContext .getInboundMessage(); - return inboundMessage; + + MOARequest request = new MOARequest(inboundMessage); + + return request; } - public Response decodeRespone(HttpServletRequest req, + public MOAResponse decodeRespone(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException{ @@ -63,7 +160,9 @@ public class PostBinding implements IDecoder, IEncoder { Response inboundMessage = (Response) messageContext .getInboundMessage(); - return inboundMessage; + + MOAResponse moaResponse = new MOAResponse(inboundMessage); + return moaResponse; } 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 d2951baf0..2cae67e97 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 @@ -1,73 +1,193 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.binding; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder; +import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; +import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.ws.security.SecurityPolicyResolver; +import org.opensaml.ws.security.provider.BasicSecurityPolicy; +import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; +import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.opensaml.xml.parse.BasicParserPool; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; public class RedirectBinding implements IDecoder, IEncoder { public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request) throws MessageDecodingException, - SecurityException { - + RequestAbstractType request, String targetLocation) + throws MessageEncodingException, SecurityException { + } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - Response response) throws MessageDecodingException, - SecurityException { - // TODO Auto-generated method stub - + StatusResponseType response, String targetLocation) + throws MessageEncodingException, SecurityException { + KeyStore keyStore; + + try { + keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + + FileInputStream inputStream = new FileInputStream( + "/home/afitzek/server/moaid_conf/moaid/pvp.ks"); + keyStore.load(inputStream, "123456".toCharArray()); + inputStream.close(); + + BasicCredential credentials = new BasicCredential(); + PrivateKey key = (PrivateKey) keyStore.getKey("pvpIDP", + "123456".toCharArray()); + Certificate cert = keyStore.getCertificate("pvpIDP"); + credentials.setPublicKey(cert.getPublicKey()); + credentials.setPrivateKey(key); + credentials.setUsageType(UsageType.SIGNING); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(credentials); + + response.setSignature(signer); + + HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( + resp, true); + BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + SingleSignOnService service = new SingleSignOnServiceBuilder() + .buildObject(); + service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-REDIRECT"); + service.setLocation(targetLocation); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + // context.setOutboundMessage(authReq); + context.setOutboundSAMLMessage(response); + context.setOutboundMessageTransport(responseAdapter); + + encoder.encode(context); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (UnrecoverableKeyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - public RequestAbstractType decodeRequest(HttpServletRequest req, + public MOARequest decodeRequest(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException { - + HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( new BasicParserPool()); - BasicSAMLMessageContext<RequestAbstractType, ?, ?> messageContext = - new BasicSAMLMessageContext<RequestAbstractType, SAMLObject, SAMLObject>(); + BasicSAMLMessageContext<RequestAbstractType, ?, ?> messageContext = new BasicSAMLMessageContext<RequestAbstractType, SAMLObject, SAMLObject>(); messageContext - .setInboundMessageTransport(new HttpServletRequestAdapter( - req)); - + .setInboundMessageTransport(new HttpServletRequestAdapter(req)); + + try { + messageContext.setMetadataProvider(new MOAMetadataProvider()); + } catch (MetadataProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); + messageContext.setSecurityPolicyResolver(resolver); decode.decode(messageContext); - RequestAbstractType inboundMessage = (RequestAbstractType)messageContext.getInboundMessage(); - - return inboundMessage; + signatureRule.evaluate(messageContext); + + RequestAbstractType inboundMessage = (RequestAbstractType) messageContext + .getInboundMessage(); + MOARequest request = new MOARequest(inboundMessage); + request.setVerified(true); + request.setEntityMetadata(messageContext.getPeerEntityMetadata()); + return request; } - public Response decodeRespone(HttpServletRequest req, + public MOAResponse decodeRespone(HttpServletRequest req, HttpServletResponse resp) throws MessageDecodingException, SecurityException { - + HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( new BasicParserPool()); - BasicSAMLMessageContext<Response, ?, ?> messageContext = - new BasicSAMLMessageContext<Response, SAMLObject, SAMLObject>(); + BasicSAMLMessageContext<Response, ?, ?> messageContext = new BasicSAMLMessageContext<Response, SAMLObject, SAMLObject>(); messageContext - .setInboundMessageTransport(new HttpServletRequestAdapter( - req)); - + .setInboundMessageTransport(new HttpServletRequestAdapter(req)); + + // TODO: used to verify signature! + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + + // signatureRule.evaluate(messageContext); + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); + messageContext.setSecurityPolicyResolver(resolver); + decode.decode(messageContext); - Response inboundMessage = (Response)messageContext.getInboundMessage(); - - return inboundMessage; + Response inboundMessage = (Response) messageContext.getInboundMessage(); + + MOAResponse moaResponse = new MOAResponse(inboundMessage); + moaResponse.setVerified(true); + moaResponse.setEntityMetadata(messageContext.getPeerEntityMetadata()); + return moaResponse; } - + public boolean handleDecode(String action) { return (action.equals(PVP2XProtocol.REDIRECT)); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java new file mode 100644 index 000000000..8dad932e2 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java @@ -0,0 +1,76 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.metadata; + +import java.io.File; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.DefaultBootstrap; +import org.opensaml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.RoleDescriptor; +import org.opensaml.saml2.metadata.provider.MetadataFilter; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; +import org.opensaml.xml.ConfigurationException; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.parse.BasicParserPool; + +public class MOAMetadataProvider implements MetadataProvider { + + MetadataProvider internalProvider; + + private static final String MD_FILE = "/home/afitzek/server/moaid_conf/moaid/metadata/samplePVP_MD.xml"; + //private static final String MD_FILE = "/home/afitzek/server/moaid_conf/moaid/metadata/md_provider.xml"; + + public MOAMetadataProvider() throws MetadataProviderException { + FilesystemMetadataProvider fsProvider = new FilesystemMetadataProvider( + new File(MD_FILE)); + fsProvider.setParserPool(new BasicParserPool()); + internalProvider = fsProvider; + fsProvider.initialize(); + } + + public boolean requireValidMetadata() { + return internalProvider.requireValidMetadata(); + } + + public void setRequireValidMetadata(boolean requireValidMetadata) { + internalProvider.setRequireValidMetadata(requireValidMetadata); + } + + public MetadataFilter getMetadataFilter() { + return internalProvider.getMetadataFilter(); + } + + public void setMetadataFilter(MetadataFilter newFilter) + throws MetadataProviderException { + internalProvider.setMetadataFilter(newFilter); + } + + public XMLObject getMetadata() throws MetadataProviderException { + return internalProvider.getMetadata(); + } + + public EntitiesDescriptor getEntitiesDescriptor(String name) + throws MetadataProviderException { + return internalProvider.getEntitiesDescriptor(name); + } + + public EntityDescriptor getEntityDescriptor(String entityID) + throws MetadataProviderException { + return internalProvider.getEntityDescriptor(entityID); + } + + public List<RoleDescriptor> getRole(String entityID, QName roleName) + throws MetadataProviderException { + return internalProvider.getRole(entityID, roleName); + } + + public RoleDescriptor getRole(String entityID, QName roleName, + String supportedProtocol) throws MetadataProviderException { + return internalProvider.getRole(entityID, roleName, supportedProtocol); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/AuthnRequestHandler.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/AuthnRequestHandler.java index cdc0a9914..4af35e325 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/AuthnRequestHandler.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/AuthnRequestHandler.java @@ -3,22 +3,109 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.ArtifactResponse; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.BaseID; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.Subject; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; + +import edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.dataConnector.StoredIDStore.PersistentIdEntry; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.moduls.AuthenticationManager; +import at.gv.egovernment.moa.id.moduls.AuthenticationSessionStore; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; +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.utils.SAML2Utils; +import at.gv.egovernment.moa.id.util.HTTPUtils; public class AuthnRequestHandler implements IRequestHandler { - public boolean handleObject(RequestAbstractType obj) { - return (obj instanceof AuthnRequest); + public boolean handleObject(MOARequest obj) { + return (obj.getSamlRequest() instanceof AuthnRequest); } - public void process(RequestAbstractType obj, HttpServletRequest req, + public void process(MOARequest obj, HttpServletRequest req, HttpServletResponse resp) { if(!handleObject(obj)) { // TODO: throw exception return; } + AuthnRequest authnRequest = (AuthnRequest)obj.getSamlRequest(); + + Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class); + + AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); + authnContextClassRef.setAuthnContextClassRef(AuthnContext.SMARTCARD_PKI_AUTHN_CTX); + + AuthnContext authnContext = SAML2Utils.createSAMLObject(AuthnContext.class); + authnContext.setAuthnContextClassRef(authnContextClassRef); + + AuthnStatement authnStatement = SAML2Utils.createSAMLObject(AuthnStatement.class); + + authnStatement.setAuthnInstant(new DateTime()); + authnStatement.setAuthnContext(authnContext); + + assertion.getAuthnStatements().add(authnStatement); + + AuthenticationSession authSession = + AuthenticationManager.getAuthenticationSession(req.getSession()); + + Subject subject = SAML2Utils.createSAMLObject(Subject.class); + NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); + subjectNameID.setFormat(NameID.PERSISTENT); + subjectNameID.setValue(authSession.getAuthData().getIdentificationValue()); + subject.setNameID(subjectNameID); + + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + issuer.setValue("pvpIDP"); + assertion.setIssuer(issuer); + assertion.setSubject(subject); + + ArtifactResponse authResponse = SAML2Utils.createSAMLObject(ArtifactResponse.class); + + Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); + nissuer.setValue("pvpIDP"); + authResponse.setIssuer(nissuer); + authResponse.setInResponseTo(authnRequest.getID()); + authResponse.setMessage(assertion); + authResponse.setStatus(SAML2Utils.getSuccessStatus()); + + Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); + int idx = 0; + + if(aIdx != null) { + idx = aIdx.intValue(); + } + + String oaURL = obj.getEntityMetadata(). + getSPSSODescriptor(SAMLConstants.SAML20P_NS). + getAssertionConsumerServices().get(idx).getLocation(); + + IEncoder binding = new PostBinding(); + try { + binding.encodeRespone(req, resp, authResponse, oaURL); + } catch (MessageEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + System.out.println("AuthnRequest"); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/IRequestHandler.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/IRequestHandler.java index a73737f15..74e8d8d4b 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/IRequestHandler.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/IRequestHandler.java @@ -5,9 +5,11 @@ import javax.servlet.http.HttpServletResponse; import org.opensaml.saml2.core.RequestAbstractType; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; + public interface IRequestHandler { - public boolean handleObject(RequestAbstractType obj); + public boolean handleObject(MOARequest obj); - public void process(RequestAbstractType obj, HttpServletRequest req, + public void process(MOARequest obj, HttpServletRequest req, HttpServletResponse resp); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java index 2fe24b707..3f1049482 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java @@ -7,9 +7,8 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.opensaml.saml2.core.RequestAbstractType; - import at.gv.egovernment.moa.id.protocols.pvp2x.SAMLRequestNotSupported; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOARequest; public class RequestManager { @@ -26,10 +25,10 @@ public class RequestManager { private RequestManager() { handler = new ArrayList<IRequestHandler>(); - + handler.add(new AuthnRequestHandler()); } - public void handle(RequestAbstractType obj, HttpServletRequest req, HttpServletResponse resp) + public void handle(MOARequest obj, HttpServletRequest req, HttpServletResponse resp) throws SAMLRequestNotSupported { Iterator<IRequestHandler> it = handler.iterator(); while(it.hasNext()) { @@ -41,6 +40,6 @@ public class RequestManager { } // not handled - throw new SAMLRequestNotSupported(); + throw new SAMLRequestNotSupported("NOTSUPPORTED", null); } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/SAMLSigner.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/SAMLSigner.java new file mode 100644 index 000000000..b88998cd1 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/SAMLSigner.java @@ -0,0 +1,5 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.signer; + +public class SAMLSigner { + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/PrettyPrinter.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/PrettyPrinter.java new file mode 100644 index 000000000..807da0ebe --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/PrettyPrinter.java @@ -0,0 +1,301 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.utils; + +import java.io.*; +import javax.xml.parsers.*; +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +import org.w3c.dom.Document; + +import org.xml.sax.*; +import org.xml.sax.helpers.*; + + +/** +This class "pretty prints" an XML stream to something more human-readable. +It duplicates the character content with some modifications to whitespace, +restoring line breaks and a simple pattern of indenting child elements. + +This version of the class acts as a SAX 2.0 <code>DefaultHandler</code>, +so to provide the unformatted XML just pass a new instance to a SAX parser. +Its output is via the {@link #toString toString} method. + +One major limitation: we gather character data for elements in a single +buffer, so mixed-content documents will lose a lot of data! This works +best with data-centric documents where elements either have single values +or child elements, but not both. + +@author Will Provost +*/ +/* +Copyright 2002-2003 by Will Provost. +All rights reserved. +*/ +public class PrettyPrinter + extends DefaultHandler +{ + /** + Convenience method to wrap pretty-printing SAX pass over existing content. + */ + public static String prettyPrint (byte[] content) + { + try + { + PrettyPrinter pretty = new PrettyPrinter (); + SAXParserFactory factory = SAXParserFactory.newInstance (); + factory.setFeature + ("http://xml.org/sax/features/namespace-prefixes", true); + factory.newSAXParser ().parse + (new ByteArrayInputStream (content), pretty); + return pretty.toString (); + } + catch (Exception ex) + { + ex.printStackTrace (); + return "EXCEPTION: " + ex.getClass ().getName () + " saying \"" + + ex.getMessage () + "\""; + } + } + + /** + Convenience method to wrap pretty-printing SAX pass over existing content. + */ + public static String prettyPrint (String content) + { + try + { + PrettyPrinter pretty = new PrettyPrinter (); + SAXParserFactory factory = SAXParserFactory.newInstance (); + factory.setFeature + ("http://xml.org/sax/features/namespace-prefixes", true); + factory.newSAXParser ().parse (content, pretty); + return pretty.toString (); + } + catch (Exception ex) + { + ex.printStackTrace (); + return "EXCEPTION: " + ex.getClass ().getName () + " saying \"" + + ex.getMessage () + "\""; + } + } + + /** + Convenience method to wrap pretty-printing SAX pass over existing content. + */ + public static String prettyPrint (InputStream content) + { + try + { + PrettyPrinter pretty = new PrettyPrinter (); + SAXParserFactory factory = SAXParserFactory.newInstance (); + factory.setFeature + ("http://xml.org/sax/features/namespace-prefixes", true); + factory.newSAXParser ().parse (content, pretty); + return pretty.toString (); + } + catch (Exception ex) + { + ex.printStackTrace (); + return "EXCEPTION: " + ex.getClass ().getName () + " saying \"" + + ex.getMessage () + "\""; + } + } + + /** + Convenience method to wrap pretty-printing SAX pass over existing content. + */ + public static String prettyPrint (Document doc) + throws TransformerException + { + try + { + ByteArrayOutputStream buffer = new ByteArrayOutputStream (); + TransformerFactory.newInstance ().newTransformer() + .transform (new DOMSource (doc), new StreamResult (buffer)); + byte[] rawResult = buffer.toByteArray (); + buffer.close (); + + return prettyPrint (rawResult); + } + catch (Exception ex) + { + ex.printStackTrace (); + return "EXCEPTION: " + ex.getClass ().getName () + " saying \"" + + ex.getMessage () + "\""; + } + } + + public static class StreamAdapter + extends OutputStream + { + public StreamAdapter (Writer finalDestination) + { + this.finalDestination = finalDestination; + } + + public void write (int b) + { + out.write (b); + } + + public void flushPretty () + throws IOException + { + PrintWriter finalPrinter = new PrintWriter (finalDestination); + finalPrinter.println + (PrettyPrinter.prettyPrint (out.toByteArray ())); + finalPrinter.close (); + out.close (); + } + + private ByteArrayOutputStream out = new ByteArrayOutputStream (); + Writer finalDestination; + } + + /** + Call this to get the formatted XML post-parsing. + */ + public String toString () + { + return output.toString (); + } + + /** + Prints the XML declaration. + */ + public void startDocument () + throws SAXException + { + output.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>") + .append (endLine); + } + + /** + Prints a blank line at the end of the reformatted document. + */ + public void endDocument () throws SAXException + { + output.append (endLine); + } + + /** + Writes the start tag for the element. + Attributes are written out, one to a text line. Starts gathering + character data for the element. + */ + public void startElement + (String URI, String name, String qName, Attributes attributes) + throws SAXException + { + if (justHitStartTag) + output.append ('>'); + + output.append (endLine) + .append (indent) + .append ('<') + .append (qName); + + int length = attributes.getLength (); + for (int a = 0; a < length; ++a) + output.append (endLine) + .append (indent) + .append (standardIndent) + .append (attributes.getQName (a)) + .append ("=\"") + .append (attributes.getValue (a)) + .append ('\"'); + + if (length > 0) + output.append (endLine) + .append (indent); + + indent += standardIndent; + currentValue = new StringBuffer (); + justHitStartTag = true; + } + + /** + Checks the {@link #currentValue} buffer to gather element content. + Writes this out if it is available. Writes the element end tag. + */ + public void endElement (String URI, String name, String qName) + throws SAXException + { + indent = indent.substring + (0, indent.length () - standardIndent.length ()); + + if (currentValue == null) + output.append (endLine) + .append (indent) + .append ("</") + .append (qName) + .append ('>'); + else if (currentValue.length () != 0) + output.append ('>') + .append (currentValue.toString ()) + .append ("</") + .append (qName) + .append ('>'); + else + output.append ("/>"); + + currentValue = null; + justHitStartTag = false; + } + + /** + When the {@link #currentValue} buffer is enabled, appends character + data into it, to be gathered when the element end tag is encountered. + */ + public void characters (char[] chars, int start, int length) + throws SAXException + { + if (currentValue != null) + currentValue.append (escape (chars, start, length)); + } + + /** + Filter to pass strings to output, escaping <b><</b> and <b>&</b> + characters to &lt; and &amp; respectively. + */ + private static String escape (char[] chars, int start, int length) + { + StringBuffer result = new StringBuffer (); + for (int c = start; c < start + length; ++c) + if (chars[c] == '<') + result.append ("<"); + else if (chars[c] == '&') + result.append ("&"); + else + result.append (chars[c]); + + return result.toString (); + } + + /** + This whitespace string is expanded and collapsed to manage the output + indenting. + */ + private String indent = ""; + + /** + A buffer for character data. It is "enabled" in + {@link #startElement startElement} by being initialized to a + new <b>StringBuffer</b>, and then read and reset to + <code>null</code> in {@link #endElement endElement}. + */ + private StringBuffer currentValue = null; + + /** + The primary buffer for accumulating the formatted XML. + */ + private StringBuffer output = new StringBuffer (); + + private boolean justHitStartTag; + + private static final String standardIndent = " "; + private static final String endLine = + System.getProperty ("line.separator"); +} + diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/SAML2Utils.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/SAML2Utils.java index 203d743be..fa2ce4f79 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/SAML2Utils.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/SAML2Utils.java @@ -1,9 +1,24 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.utils; +import java.io.IOException; + import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; import org.opensaml.Configuration; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusMessage; +import org.opensaml.xml.XMLObject; import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.id.moduls.NoPassivAuthenticationException; public class SAML2Utils { @@ -22,4 +37,33 @@ public class SAML2Utils { return null; } } + + private static DocumentBuilder builder; + static { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static Document asDOMDocument(XMLObject object) throws IOException, + MarshallingException, TransformerException { + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory().getMarshaller( + object); + out.marshall(object, document); + return document; + } + + public static Status getSuccessStatus() { + Status status = SAML2Utils.createSAMLObject(Status.class); + StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); + statusCode.setValue(StatusCode.SUCCESS_URI); + status.setStatusCode(statusCode); + return status; + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ChainSAMLValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ChainSAMLValidator.java new file mode 100644 index 000000000..bf30c72cb --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ChainSAMLValidator.java @@ -0,0 +1,28 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.validation; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.opensaml.saml2.core.RequestAbstractType; + +import at.gv.egovernment.moa.id.MOAIDException; + +public class ChainSAMLValidator implements ISAMLValidator { + +private List<ISAMLValidator> validator = new ArrayList<ISAMLValidator>(); + + public void addValidator(ISAMLValidator validator) { + this.validator.add(validator); + } + + public void validateRequest(RequestAbstractType request) + throws MOAIDException { + Iterator<ISAMLValidator> validatorIterator = validator.iterator(); + while(validatorIterator.hasNext()) { + ISAMLValidator validator = validatorIterator.next(); + validator.validateRequest(request); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ISAMLValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ISAMLValidator.java new file mode 100644 index 000000000..525a0870e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/ISAMLValidator.java @@ -0,0 +1,9 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.validation; + +import org.opensaml.saml2.core.RequestAbstractType; + +import at.gv.egovernment.moa.id.MOAIDException; + +public interface ISAMLValidator { + public void validateRequest(RequestAbstractType request) throws MOAIDException; +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/SAMLSignatureValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/SAMLSignatureValidator.java new file mode 100644 index 000000000..95c548389 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/SAMLSignatureValidator.java @@ -0,0 +1,27 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.validation; + +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.xml.validation.ValidationException; + +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.protocols.pvp2x.SAMLRequestNotSignedException; + +public class SAMLSignatureValidator implements ISAMLValidator { + + public void validateRequest(RequestAbstractType request) + throws MOAIDException { + if(request.getSignature() == null) { + throw new SAMLRequestNotSignedException("NOT SIGNED", new Object[] {}); + } + + try { + SAMLSignatureProfileValidator sigValidator = new SAMLSignatureProfileValidator(); + sigValidator.validate(request.getSignature()); + } catch (ValidationException e) { + e.printStackTrace(); + throw new MOAIDException("SIGNATURE VALIDATOR", new Object[] {}); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ChainSAMLVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ChainSAMLVerifier.java new file mode 100644 index 000000000..5cea607bc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ChainSAMLVerifier.java @@ -0,0 +1,28 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.verification; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.opensaml.saml2.core.RequestAbstractType; + +import at.gv.egovernment.moa.id.MOAIDException; + +public class ChainSAMLVerifier implements ISAMLVerifier { + + private List<ISAMLVerifier> verifier = new ArrayList<ISAMLVerifier>(); + + public void addVerifier(ISAMLVerifier verifier) { + this.verifier.add(verifier); + } + + public void verifyRequest(RequestAbstractType request) + throws MOAIDException { + Iterator<ISAMLVerifier> verifyIterator = verifier.iterator(); + while(verifyIterator.hasNext()) { + ISAMLVerifier verifier = verifyIterator.next(); + verifier.verifyRequest(request); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ISAMLVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ISAMLVerifier.java new file mode 100644 index 000000000..a577f3f46 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/ISAMLVerifier.java @@ -0,0 +1,9 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.verification; + +import org.opensaml.saml2.core.RequestAbstractType; + +import at.gv.egovernment.moa.id.MOAIDException; + +public interface ISAMLVerifier { + public void verifyRequest(RequestAbstractType request) throws MOAIDException; +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java new file mode 100644 index 000000000..af77213df --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java @@ -0,0 +1,108 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.verification; + +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.xml.validation.ValidationException; +import org.w3c.dom.Element; + +import eu.stork.vidp.messages.util.SAMLUtil; +import eu.stork.vidp.messages.util.XMLUtil; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.auth.builder.VerifyXMLSignatureRequestBuilder; +import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; +import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.logging.Logger; + +public class SAMLVerifierMOASP implements ISAMLVerifier { + + public void verifyRequest(RequestAbstractType request) + throws MOAIDException { + // validate Signature + try { + if (request.isSigned()) { + + String trustProfileID = AuthConfigurationProvider.getInstance() + .getStorkConfig().getSignatureVerificationParameter() + .getTrustProfileID(); + + Logger.trace("Starting validation of Signature references"); + try { + SAMLSignatureProfileValidator sigValidator = new SAMLSignatureProfileValidator(); + sigValidator.validate(request.getSignature()); + } catch (ValidationException e) { + Logger.error("Validation of XML Signature refrences failed: " + + e.getMessage()); + throw new SecurityException(e); + } + Logger.debug("XML Signature references are OK."); + + Logger.debug("Invoking MOA-SP with TrustProfileID: " + + trustProfileID); + + // builds a <VerifyXMLSignatureRequest> for a call of MOA-SP + Element domVerifyXMLSignatureRequest = new VerifyXMLSignatureRequestBuilder() + .build(XMLUtil.printXML(request.getDOM()).getBytes(), + trustProfileID); + + Logger.trace("VerifyXMLSignatureRequest for MOA-SP succesfully built"); + + Logger.trace("Calling MOA-SP"); + // invokes the call + Element domVerifyXMLSignatureResponse = new SignatureVerificationInvoker() + .verifyXMLSignature(domVerifyXMLSignatureRequest); + + // parses the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser( + domVerifyXMLSignatureResponse).parseData(); + + Logger.trace("Received VerifyXMLSignatureResponse from MOA-SP"); + + if (verifyXMLSignatureResponse.getSignatureCheckCode() != 0) { + String msg = "Signature of SAMLResponse not valid"; + Logger.error(msg); + throw new SecurityException(msg); + } + + Logger.debug("Signature of SAML response successfully verified"); + + if (verifyXMLSignatureResponse.getCertificateCheckCode() != 0) { + String msg = "Certificate of SAMLResponse not valid"; + Logger.error(msg); + throw new SecurityException(msg); + } + + Logger.debug("Signing certificate of SAML response succesfully verified"); + + } else { + String msg = "SAML Response is not signed."; + throw new SecurityException(msg); + } + + } catch (ConfigurationException e) { + String msg = "Unable to load STORK configuration for STORK SAML Response signature verification."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } catch (ParseException e) { + String msg = "Unable to parse VerifyXMLSignature Request or Response."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } catch (BuildException e) { + String msg = "Unable to parse VerifyXMLSignature Request or Response."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } catch (ServiceException e) { + String msg = "Unable to invoke MOA-SP."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/TrustEngineFactory.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/TrustEngineFactory.java new file mode 100644 index 000000000..8e4e88031 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/TrustEngineFactory.java @@ -0,0 +1,70 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.verification; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.security.MetadataCredentialResolver; +import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; +import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; +import org.opensaml.xml.signature.impl.PKIXSignatureTrustEngine; + +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import edu.internet2.middleware.shibboleth.common.security.MetadataPKIXValidationInformationResolver; + +public class TrustEngineFactory { + + public static SignatureTrustEngine getSignatureTrustEngine() { + try { + MetadataPKIXValidationInformationResolver mdResolver = new MetadataPKIXValidationInformationResolver( + new MOAMetadataProvider()); + + List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + + KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + PKIXSignatureTrustEngine engine = new PKIXSignatureTrustEngine( + mdResolver, keyInfoResolver); + + return engine; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static SignatureTrustEngine getSignatureKnownKeysTrustEngine() { + MetadataCredentialResolver resolver; + try { + resolver = new MetadataCredentialResolver(new MOAMetadataProvider()); + + List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + + KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + ExplicitKeySignatureTrustEngine engine = new ExplicitKeySignatureTrustEngine( + resolver, keyInfoResolver); + + return engine; + } catch (MetadataProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java index d4ee5f46c..5649e5260 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java @@ -124,4 +124,8 @@ public class GetArtifactAction implements IAction { return true; } + public String getDefaultActionName() { + return SAML1Protocol.GETARTIFACT; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java index fbb296a9e..d184643c4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java @@ -85,4 +85,9 @@ public class SAML1Protocol implements IModulInfo, MOAIDAuthConstants { return actions.get(action); } + public IAction canHandleRequest(HttpServletRequest request, + HttpServletResponse response) { + return null; + } + } diff --git a/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html b/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html new file mode 100644 index 000000000..1215c2b58 --- /dev/null +++ b/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html @@ -0,0 +1,51 @@ +## +## Velocity Template for SAML 2 HTTP-POST binding +## +## Velocity context may contain the following properties +## action - String - the action URL for the form +## RelayState - String - the relay state for the message +## SAMLRequest - String - the Base64 encoded SAML Request +## SAMLResponse - String - the Base64 encoded SAML Response + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + + <body onload="document.forms[0].submit()"> + <noscript> + <p> + <strong>Note:</strong> Since your browser does not support JavaScript, + you must press the Continue button once to proceed. + </p> + </noscript> + + + <div id="alert">Your login is being processed. Thank you for waiting.</div> + + <style type="text/css"> + <!-- + #alert { + margin:100px 250px; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size:14px; + font-weight:normal; + } + --> + </style> + + <form action="${action}" method="post"> + <div> + #if($RelayState)<input type="hidden" name="RelayState" value="${RelayState}"/>#end + + #if($SAMLRequest)<input type="hidden" name="SAMLRequest" value="${SAMLRequest}"/>#end + + #if($SAMLResponse)<input type="hidden" name="SAMLResponse" value="${SAMLResponse}"/>#end + + </div> + <noscript> + <div> + <input type="submit" value="Continue"/> + </div> + </noscript> + </form> + + </body> +</html>
\ No newline at end of file |