diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols')
38 files changed, 3207 insertions, 1564 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/AbstractAuthProtocolModulController.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/AbstractAuthProtocolModulController.java new file mode 100644 index 000000000..bb89f2e03 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/AbstractAuthProtocolModulController.java @@ -0,0 +1,272 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataBuilder; +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.servlet.AbstractController; +import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +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.IModulInfo; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.moduls.SSOManager; +import at.gv.egovernment.moa.id.storage.IAuthenticationSessionStoreage; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ + +public abstract class AbstractAuthProtocolModulController extends AbstractController implements IModulInfo { + + public static final String FINALIZEPROTOCOL_ENDPOINT = "finalizeAuthProtocol"; + + @Autowired protected ApplicationContext applicationContext; + @Autowired private SSOManager ssomanager; + @Autowired protected AuthenticationManager authmanager; + @Autowired protected IAuthenticationSessionStoreage authenticatedSessionStorage; + @Autowired private AuthenticationDataBuilder authDataBuilder; + + /** + * Initialize an authentication process for this protocol request + * + * @param httpReq HttpServletRequest + * @param httpResp HttpServletResponse + * @param protocolRequest Authentication request which is actually in process + * @throws IOException + */ + protected void performAuthentication(HttpServletRequest req, HttpServletResponse resp, + RequestImpl pendingReq) throws IOException { + try { + if (pendingReq.isNeedAuthentication()) { + //request needs authentication --> start authentication process ... + + //load Parameters from OnlineApplicationConfiguration + IOAAuthParameters oaParam = pendingReq.getOnlineApplicationConfiguration(); + + if (oaParam == null) { + throw new AuthenticationException("auth.00", new Object[] { pendingReq.getOAURL() }); + } + + + AuthenticationSession moaSession = authmanager.doAuthentication(req, resp, pendingReq); + if (moaSession != null) { + //authenticated MOASession already exists --> protocol-specific postProcessing can start directly + finalizeAuthenticationProcess(req, resp, pendingReq, moaSession); + + } + + } else { + executeProtocolSpecificAction(req, resp, pendingReq, null); + + } + + } catch (Exception e) { + buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); + + } + } + + /** + * Finalize the requested protocol operation + * + * @param httpReq HttpServletRequest + * @param httpResp HttpServletResponse + * @param protocolRequest Authentication request which is actually in process + * @param moaSession MOASession object, which is used to generate the protocol specific authentication information + * @throws Exception + */ + protected void finalizeAuthenticationProcess(HttpServletRequest req, HttpServletResponse resp, + IRequest pendingReq, AuthenticationSession moaSession) throws Exception { + + String newSSOSessionId = null; + + //if Single Sign-On functionality is enabled for this request + if (pendingReq.needSingleSignOnFunctionality()) { + + //Store SSO information into database + newSSOSessionId = ssomanager.createSSOSessionInformations(moaSession.getSessionID(), + pendingReq.getOAURL()); + + //set SSO cookie to response + if (MiscUtil.isNotEmpty(newSSOSessionId)) { + ssomanager.setSSOSessionID(req, resp, newSSOSessionId); + + } else { + ssomanager.deleteSSOSessionID(req, resp); + + } + + } + + //build authenticationdata from session information and OA configuration + IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq, moaSession); + + //execute the protocol-specific action + SLOInformationInterface sloInformation = executeProtocolSpecificAction(req, resp, pendingReq, authData); + + //check if SSO + boolean isSSOCookieSetted = MiscUtil.isNotEmpty(newSSOSessionId); + + //Store OA specific SSO session information if an SSO cookie is set + if (isSSOCookieSetted) { + try { + authenticatedSessionStorage.addSSOInformation(moaSession.getSessionID(), + newSSOSessionId, sloInformation, pendingReq); + + } catch (AuthenticationException e) { + Logger.warn("SSO Session information can not be stored -> SSO is not enabled!"); + authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); + + } + + } else { + //remove MOASession from database + authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); + + } + + //Advanced statistic logging + statisticLogger.logSuccessOperation(pendingReq, authData, isSSOCookieSetted); + + } + + /** + * Executes the requested protocol action + * + * @param httpReq HttpServletRequest + * @param httpResp HttpServletResponse + * @param protocolRequest Authentication request which is actually in process + * @param authData Service-provider specific authentication data + * + * @return Return Single LogOut information or null if protocol supports no SSO + * + * @throws Exception + */ + private SLOInformationInterface executeProtocolSpecificAction(HttpServletRequest httpReq, HttpServletResponse httpResp, + IRequest pendingReq, IAuthData authData) throws Exception { + try { + // request needs no authentication --> start request processing + Class<?> clazz = Class.forName(pendingReq.requestedAction()); + if (clazz == null || + !IAction.class.isAssignableFrom(clazz)) { + Logger.fatal("Requested protocol-action processing Class is NULL or does not implement the IAction interface."); + throw new Exception("Requested protocol-action processing Class is NULL or does not implement the IAction interface."); + + } + + IAction protocolAction = (IAction) applicationContext.getBean(clazz); + return protocolAction.processRequest(pendingReq, httpReq, httpResp, authData); + + } catch (ClassNotFoundException e) { + Logger.fatal("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); + throw new Exception("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); + } + + } + + protected void buildProtocolSpecificErrorResponse(Throwable throwable, HttpServletRequest req, + HttpServletResponse resp, IRequest protocolRequest) throws IOException { + try { + + Class<?> clazz = Class.forName(protocolRequest.requestedModule()); + if (clazz == null || + !clazz.isInstance(IModulInfo.class)) { + Logger.fatal("Requested protocol module Class is NULL or does not implement the IModulInfo interface."); + throw new Exception("Requested protocol module Class is NULL or does not implement the IModulInfo interface."); + + } + + IModulInfo handlingModule = (IModulInfo) applicationContext.getBean(clazz); + + if (handlingModule.generateErrorMessage( + throwable, req, resp, protocolRequest)) { + + //log Error to technical log + logExceptionToTechnicalLog(throwable); + + //log Error Message + statisticLogger.logErrorOperation(throwable, protocolRequest); + + //remove MOASession + AuthenticationSession moaSession = authenticatedSessionStorage.getSession( + protocolRequest.getMOASessionIdentifier()); + if (moaSession != null) + authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); + + return; + + } else { + handleErrorNoRedirect(throwable, req, resp, true); + + } + + } catch (Throwable e) { + Logger.error(e); + handleErrorNoRedirect(throwable, req, resp, true); + + } + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IModulInfo#getName() + */ + @Override + public abstract String getName(); + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IModulInfo#getPath() + */ + @Override + public abstract String getPath(); + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IModulInfo#generateErrorMessage(java.lang.Throwable, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) + */ + @Override + public abstract boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, + IRequest protocolRequest) throws Throwable; + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IModulInfo#validate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) + */ + @Override + public abstract boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/ProtocolFinalizationController.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/ProtocolFinalizationController.java new file mode 100644 index 000000000..8c3f2c946 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/ProtocolFinalizationController.java @@ -0,0 +1,201 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +@Controller +public class ProtocolFinalizationController extends AbstractAuthProtocolModulController { + + @RequestMapping(value = "/finalizeAuthProtocol", method = {RequestMethod.GET}) + public void finalizeAuthProtocol(HttpServletRequest req, HttpServletResponse resp) throws MOAIDException, IOException { + + //read pendingRequest from http request + Object idObject = req.getParameter(PARAM_TARGET_PENDINGREQUESTID); + IRequest pendingReq = null; + String pendingRequestID = null; + if (idObject != null && (idObject instanceof String)) { + pendingRequestID = (String) idObject; + pendingReq = requestStorage.getPendingRequest(pendingRequestID); + + } + + //receive an authentication error + String errorid = req.getParameter(ERROR_CODE_PARAM); + if (errorid != null) { + try { + //load stored exception from database + Throwable throwable = transactionStorage.get(errorid, Throwable.class); + transactionStorage.remove(errorid); + + if (throwable != null) { + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.TRANSACTION_ERROR); + + //build protocol-specific error message if possible + buildProtocolSpecificErrorResponse(throwable, req, resp, pendingReq); + + //log Error Message + statisticLogger.logErrorOperation(throwable, pendingReq); + + //get MOASession for this pendingRequest + AuthenticationSession moaSession = + authenticatedSessionStorage.getSession( + pendingReq.getMOASessionIdentifier()); + + //remove MOASession if someone is found + if (moaSession != null) + authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); + + return; + + } else { + handleErrorNoRedirect(throwable, req, resp, true); + + } + } else { + handleErrorNoRedirect(new Exception( + MOAIDMessageProvider.getInstance().getMessage("auth.26", null)), + req, resp, false); + + } + + } catch (Throwable e) { + Logger.error(e); + + handleErrorNoRedirect(e, req, resp, false); + + } + + // receive a pending request + } else { + if (pendingReq == null) { + Logger.error("No PendingRequest with ID " + pendingRequestID + " found.!"); + handleErrorNoRedirect(new MOAIDException("auth.28", new Object[]{pendingRequestID}), req, resp, false); + return; + + } + try { + Logger.debug("Finalize PendingRequest with ID " + pendingRequestID); + + //get MOASession from database + String sessionID = pendingReq.getMOASessionIdentifier(); + + // check parameter + if (!ParamValidatorUtils.isValidSessionID(sessionID)) { + throw new WrongParametersException("FinalizeAuthProtocol", PARAM_SESSIONID, "auth.12"); + + } + + //load MOASession from database + AuthenticationSession moaSession = authenticatedSessionStorage.getSession(sessionID); + if (moaSession == null) { + Logger.error("No MOASession with ID " + sessionID + " found.!"); + handleErrorNoRedirect(new MOAIDException("auth.02", new Object[]{sessionID}), req, resp, true); + return; + + } + + //check if MOASession and pending-request are authenticated + if (moaSession.isAuthenticated() && pendingReq.isAuthenticated()) { + finalizeAuthenticationProcess(req, resp, pendingReq, moaSession); + + } else { + Logger.error("MOASession oder Pending-Request are not authenticated --> Abort authentication process!"); + handleErrorNoRedirect(new MOAIDException("auth.20", null), req, resp, true); + return; + + } + + } catch (Exception e) { + Logger.error("Finalize authentication protocol FAILED." , e); + buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); + + } + } + + //remove pending-request + if (pendingReq != null) + requestStorage.removePendingRequest(pendingReq.getRequestID()); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.AbstractProtocolModulController#getName() + */ + @Override + public String getName() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.AbstractProtocolModulController#getPath() + */ + @Override + public String getPath() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.AbstractProtocolModulController#generateErrorMessage(java.lang.Throwable, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) + */ + @Override + public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, + IRequest protocolRequest) throws Throwable { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.AbstractProtocolModulController#validate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) + */ + @Override + public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { + // TODO Auto-generated method stub + return false; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AttributQueryAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AttributQueryAction.java index 9f8b6610f..bd6399377 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AttributQueryAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/AttributQueryAction.java @@ -24,6 +24,7 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -36,8 +37,8 @@ import org.opensaml.saml2.core.AttributeQuery; import org.opensaml.saml2.core.Response; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.xml.security.SecurityException; - -import java.util.Arrays; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; @@ -51,15 +52,21 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AuthResponseBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.assertion.PVP2AssertionBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AttributQueryException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; -import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; +import at.gv.egovernment.moa.id.storage.IAuthenticationSessionStoreage; import at.gv.egovernment.moa.logging.Logger; /** * @author tlenz * */ +@Service("AttributQueryAction") public class AttributQueryAction implements IAction { + @Autowired IAuthenticationSessionStoreage authenticationSessionStorage; + @Autowired private AuthenticationDataBuilder authDataBuilder; + @Autowired private IDPCredentialProvider pvpCredentials; + private final static List<String> DEFAULTSTORKATTRIBUTES = Arrays.asList( new String[]{PVPConstants.EID_STORK_TOKEN_NAME}); @@ -86,7 +93,7 @@ public class AttributQueryAction implements IAction { //load moaSession String nameID = attrQuery.getSubject().getNameID().getValue(); - AuthenticationSession session = AuthenticationSessionStoreage.getSessionWithUserNameID(nameID); + AuthenticationSession session = authenticationSessionStorage.getSessionWithUserNameID(nameID); if (session == null) { Logger.warn("AttributeQuery nameID does not match to an active single sign-on session."); throw new AttributQueryException("AttributeQuery nameID does not match to an active single sign-on session.", null); @@ -96,20 +103,21 @@ public class AttributQueryAction implements IAction { DateTime date = new DateTime(); //generate authData - authData = AuthenticationDataBuilder.buildAuthenticationData(req, session, attrQuery.getAttributes()); + authData = authDataBuilder.buildAuthenticationData(req, session, attrQuery.getAttributes()); //add default attributes in case of mandates or STORK is in use List<String> attrList = addDefaultAttributes(attrQuery, authData); //build PVP 2.1 assertion - Assertion assertion = PVP2AssertionBuilder.buildAssertion(attrQuery, attrList, authData, date, authData.getSessionIndex()); + Assertion assertion = PVP2AssertionBuilder.buildAssertion(req, attrQuery, attrList, authData, date, authData.getSessionIndex()); //build PVP 2.1 response - Response authResponse = AuthResponseBuilder.buildResponse(attrQuery, date, assertion); + Response authResponse = AuthResponseBuilder.buildResponse(req.getAuthURL(), attrQuery, date, assertion); try { SoapBinding decoder = new SoapBinding(); - decoder.encodeRespone(httpReq, httpResp, authResponse, null, null); + decoder.encodeRespone(httpReq, httpResp, authResponse, null, null, + pvpCredentials.getIDPAssertionSigningCredential()); return null; } catch (MessageEncodingException e) { 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 04b7854b1..21f505bf1 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 @@ -25,27 +25,99 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; 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.Assertion; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; 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; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AuthResponseBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.assertion.PVP2AssertionBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.logging.Logger; +@Service("PVPAuthenticationRequestAction") public class AuthenticationAction implements IAction { - + @Autowired IDPCredentialProvider pvpCredentials; + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { PVPTargetConfiguration pvpRequest = (PVPTargetConfiguration) req; - SLOInformationImpl sloInformation = (SLOInformationImpl) RequestManager.getInstance().handle(pvpRequest, httpReq, httpResp, authData); + //get basic information + MOARequest moaRequest = (MOARequest) pvpRequest.getRequest(); + AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest(); + EntityDescriptor peerEntity = moaRequest.getEntityMetadata(); + + AssertionConsumerService consumerService = + SAML2Utils.createSAMLObject(AssertionConsumerService.class); + consumerService.setBinding(pvpRequest.getBinding()); + consumerService.setLocation(pvpRequest.getConsumerURL()); + + DateTime date = new DateTime(); + + SLOInformationImpl sloInformation = new SLOInformationImpl(); + + //build Assertion + Assertion assertion = PVP2AssertionBuilder.buildAssertion(pvpRequest, authnRequest, authData, + peerEntity, date, consumerService, sloInformation); + + Response authResponse = AuthResponseBuilder.buildResponse(pvpRequest.getAuthURL(), authnRequest, date, assertion); + + IEncoder binding = null; - //set protocol type - sloInformation.setProtocolType(req.requestedModule()); + 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(httpReq, httpResp, authResponse, + consumerService.getLocation(), moaRequest.getRelayState(), + pvpCredentials.getIDPAssertionSigningCredential()); + + //set protocol type + sloInformation.setProtocolType(req.requestedModule()); + return sloInformation; + + } 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); + + } - return sloInformation; } public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, @@ -54,7 +126,8 @@ public class AuthenticationAction implements IAction { } public String getDefaultActionName() { - return (PVP2XProtocol.REDIRECT); + return "PVPAuthenticationRequestAction"; + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java index 1b187d82e..15fe1e9d7 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java @@ -22,150 +22,44 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x; -import java.io.StringWriter; -import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import org.joda.time.DateTime; -import org.opensaml.Configuration; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.ContactPerson; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.KeyDescriptor; -import org.opensaml.saml2.metadata.LocalizedString; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.RoleDescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.ServiceName; -import org.opensaml.saml2.metadata.SingleLogoutService; -import org.opensaml.saml2.metadata.SingleSignOnService; -import org.opensaml.xml.io.Marshaller; -import org.opensaml.xml.security.SecurityException; -import org.opensaml.xml.security.SecurityHelper; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; -import org.opensaml.xml.signature.Signature; -import org.opensaml.xml.signature.Signer; -import org.w3c.dom.Document; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationInterface; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IRequest; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPMetadataBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IDPPVPMetadataConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPMetadataBuilderConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; import at.gv.egovernment.moa.logging.Logger; +@Service("pvpMetadataService") public class MetadataAction implements IAction { - private static final int VALIDUNTIL_IN_HOURS = 24; - + + + @Autowired private MOAReversionLogger revisionsLogger; + @Autowired private IDPCredentialProvider credentialProvider; + @Autowired private PVPMetadataBuilder metadatabuilder; + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { try { - - MOAReversionLogger.getInstance().logEvent(req, MOAIDEventConstants.AUTHPROTOCOL_PVP_METADATA); - - EntitiesDescriptor idpEntitiesDescriptor = - SAML2Utils.createSAMLObject(EntitiesDescriptor.class); - - idpEntitiesDescriptor.setName(PVPConfiguration.getInstance().getIDPIssuerName()); - - idpEntitiesDescriptor.setID(SAML2Utils.getSecureIdentifier()); - - DateTime date = new DateTime(); + revisionsLogger.logEvent(req, MOAIDEventConstants.AUTHPROTOCOL_PVP_METADATA); - idpEntitiesDescriptor.setValidUntil(date.plusHours(VALIDUNTIL_IN_HOURS)); - - EntityDescriptor idpEntityDescriptor = SAML2Utils - .createSAMLObject(EntityDescriptor.class); - - idpEntitiesDescriptor.getEntityDescriptors().add(idpEntityDescriptor); + //build metadata + IPVPMetadataBuilderConfiguration metadataConfig = + new IDPPVPMetadataConfiguration(req.getAuthURLWithOutSlash(), credentialProvider); - //TODO: maybe change EntityID to Metadata URL - //idpEntityDescriptor - // .setEntityID(PVPConfiguration.getInstance().getIDPSSOMetadataService()); - - idpEntityDescriptor - .setEntityID(PVPConfiguration.getInstance().getIDPPublicPath()); - - idpEntityDescriptor.setValidUntil(date.plusDays(VALIDUNTIL_IN_HOURS)); - - List<ContactPerson> persons = PVPConfiguration.getInstance() - .getIDPContacts(); - - idpEntityDescriptor.getContactPersons().addAll(persons); - - idpEntityDescriptor.setOrganization(PVPConfiguration.getInstance() - .getIDPOrganisation()); - - X509KeyInfoGeneratorFactory keyInfoFactory = new X509KeyInfoGeneratorFactory(); - //keyInfoFactory.setEmitPublicKeyValue(true); - keyInfoFactory.setEmitEntityIDAsKeyName(true); - keyInfoFactory.setEmitEntityCertificate(true); - - KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); - - Credential metadataSigningCredential = CredentialProvider.getIDPMetaDataSigningCredential(); - Signature signature = CredentialProvider - .getIDPSignature(metadataSigningCredential); - - //set KeyInfo Element - SecurityHelper.prepareSignatureParams(signature, metadataSigningCredential, null, null); - - idpEntitiesDescriptor.setSignature(signature); - - //set IDP metadata - idpEntityDescriptor.getRoleDescriptors().add(generateIDPMetadata(keyInfoGenerator)); - - //set SP metadata for interfederation - idpEntityDescriptor.getRoleDescriptors().add(generateSPMetadata(keyInfoGenerator)); - - DocumentBuilder builder; - DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); - - builder = factory.newDocumentBuilder(); - Document document = builder.newDocument(); - Marshaller out = Configuration.getMarshallerFactory() - .getMarshaller(idpEntitiesDescriptor); - out.marshall(idpEntitiesDescriptor, document); - - Signer.signObject(signature); - - Transformer transformer = TransformerFactory.newInstance() - .newTransformer(); - - StringWriter sw = new StringWriter(); - StreamResult sr = new StreamResult(sw); - DOMSource source = new DOMSource(document); - transformer.transform(source, sr); - sw.close(); - - String metadataXML = sw.toString(); + String metadataXML = metadatabuilder.buildPVPMetadata(metadataConfig); Logger.debug("METADATA: " + metadataXML); httpResp.setContentType("text/xml"); @@ -186,232 +80,12 @@ public class MetadataAction implements IAction { return false; } + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + @Override public String getDefaultActionName() { - return (PVP2XProtocol.METADATA); + return "IDP - PVP Metadata action"; } - private RoleDescriptor generateSPMetadata(KeyInfoGenerator keyInfoGenerator) throws CredentialsNotAvailableException, SecurityException, ConfigurationException { - - Logger.debug("Set SP Metadata key information"); - - SPSSODescriptor spSSODescriptor = SAML2Utils - .createSAMLObject(SPSSODescriptor.class); - - spSSODescriptor.setAuthnRequestsSigned(true); - spSSODescriptor.setWantAssertionsSigned(false); - - - //Set AuthRequest Signing certificate - X509Credential authcredential = CredentialProvider.getIDPAssertionSigningCredential(); - - KeyDescriptor signKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - signKeyDescriptor.setUse(UsageType.SIGNING); - signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential)); - spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); - - - //set AuthRequest encryption certificate - - X509Credential authEncCredential = CredentialProvider.getIDPAssertionEncryptionCredential(); - - if (authEncCredential != null) { - KeyDescriptor encryKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - encryKeyDescriptor.setUse(UsageType.ENCRYPTION); - encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential)); - spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor); - - } else { - Logger.warn("No Assertion Encryption-Key defined. This setting is not recommended!"); - - } - - NameIDFormat persistentnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - persistentnameIDFormat.setFormat(NameIDType.PERSISTENT); - - spSSODescriptor.getNameIDFormats().add(persistentnameIDFormat); - - NameIDFormat transientnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - transientnameIDFormat.setFormat(NameIDType.TRANSIENT); - - spSSODescriptor.getNameIDFormats().add(transientnameIDFormat); - - NameIDFormat unspecifiednameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - unspecifiednameIDFormat.setFormat(NameIDType.UNSPECIFIED); - - spSSODescriptor.getNameIDFormats().add(unspecifiednameIDFormat); - - //add assertion consumer services - AssertionConsumerService postassertionConsumerService = - SAML2Utils.createSAMLObject(AssertionConsumerService.class); - postassertionConsumerService.setIndex(0); - postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - postassertionConsumerService.setLocation(PVPConfiguration - .getInstance().getSPSSOPostService()); - postassertionConsumerService.setIsDefault(true); - spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); - - AssertionConsumerService redirectassertionConsumerService = - SAML2Utils.createSAMLObject(AssertionConsumerService.class); - redirectassertionConsumerService.setIndex(1); - redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - redirectassertionConsumerService.setLocation(PVPConfiguration - .getInstance().getSPSSORedirectService()); - spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService); - - - //add SLO descriptor -// SingleLogoutService postSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// postSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// postSLOService -// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); -// spSSODescriptor.getSingleLogoutServices().add(postSLOService); - - SingleLogoutService redirectSLOService = - SAML2Utils.createSAMLObject(SingleLogoutService.class); - redirectSLOService.setLocation(PVPConfiguration - .getInstance().getSPSSORedirectService()); - redirectSLOService - .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); - - - spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); - - AttributeConsumingService attributeService = - SAML2Utils.createSAMLObject(AttributeConsumingService.class); - - attributeService.setIndex(0); - attributeService.setIsDefault(true); - ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class); - serviceName.setName(new LocalizedString("Default Service", "de")); - attributeService.getNames().add(serviceName); - - return spSSODescriptor; - } - - private IDPSSODescriptor generateIDPMetadata(KeyInfoGenerator keyInfoGenerator) throws ConfigurationException, CredentialsNotAvailableException, SecurityException { - - -// //set SignatureMethode -// signature.setSignatureAlgorithm(PVPConstants.DEFAULT_SIGNING_METHODE); -// -// //set DigestMethode -// List<ContentReference> contentList = signature.getContentReferences(); -// for (ContentReference content : contentList) { -// -// if (content instanceof SAMLObjectContentReference) { -// -// SAMLObjectContentReference el = (SAMLObjectContentReference) content; -// el.setDigestAlgorithm(PVPConstants.DEFAULT_DIGESTMETHODE); -// -// } -// } - - -// KeyInfoBuilder metadataKeyInfoBuilder = new KeyInfoBuilder(); -// KeyInfo metadataKeyInfo = metadataKeyInfoBuilder.buildObject(); -// //KeyInfoHelper.addCertificate(metadataKeyInfo, metadataSigningCredential.); -// signature.setKeyInfo(metadataKeyInfo ); - - - IDPSSODescriptor idpSSODescriptor = SAML2Utils - .createSAMLObject(IDPSSODescriptor.class); - - idpSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); - - idpSSODescriptor.setWantAuthnRequestsSigned(true); - - if (PVPConfiguration.getInstance().getIDPSSOPostService() != null) { - //add SSO descriptor - SingleSignOnService postSingleSignOnService = SAML2Utils - .createSAMLObject(SingleSignOnService.class); - postSingleSignOnService.setLocation(PVPConfiguration - .getInstance().getIDPSSOPostService()); - postSingleSignOnService - .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - idpSSODescriptor.getSingleSignOnServices().add( - postSingleSignOnService); - - //add SLO descriptor -// SingleLogoutService postSLOService = -// SAML2Utils.createSAMLObject(SingleLogoutService.class); -// postSLOService.setLocation(PVPConfiguration -// .getInstance().getIDPSSOPostService()); -// postSLOService -// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); -// idpSSODescriptor.getSingleLogoutServices().add(postSLOService); - - } - - if (PVPConfiguration.getInstance().getIDPSSORedirectService() != null) { - //add SSO descriptor - SingleSignOnService redirectSingleSignOnService = SAML2Utils - .createSAMLObject(SingleSignOnService.class); - redirectSingleSignOnService.setLocation(PVPConfiguration - .getInstance().getIDPSSORedirectService()); - redirectSingleSignOnService - .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - idpSSODescriptor.getSingleSignOnServices().add( - redirectSingleSignOnService); - - //add SLO descriptor - SingleLogoutService redirectSLOService = - SAML2Utils.createSAMLObject(SingleLogoutService.class); - redirectSLOService.setLocation(PVPConfiguration - .getInstance().getIDPSSORedirectService()); - redirectSLOService - .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService); - } - - /*if (PVPConfiguration.getInstance().getIDPResolveSOAPService() != null) { - ArtifactResolutionService artifactResolutionService = SAML2Utils - .createSAMLObject(ArtifactResolutionService.class); - - artifactResolutionService - .setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); - artifactResolutionService.setLocation(PVPConfiguration - .getInstance().getIDPResolveSOAPService()); - - artifactResolutionService.setIndex(0); - - idpSSODescriptor.getArtifactResolutionServices().add( - artifactResolutionService); - }*/ - - //set assertion signing key - Credential assertionSigingCredential = CredentialProvider - .getIDPAssertionSigningCredential(); - - KeyDescriptor signKeyDescriptor = SAML2Utils - .createSAMLObject(KeyDescriptor.class); - signKeyDescriptor.setUse(UsageType.SIGNING); - signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(assertionSigingCredential)); - idpSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); - - idpSSODescriptor.getAttributes().addAll(PVPAttributeBuilder.buildSupportedEmptyAttributes()); - - NameIDFormat persistenNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - persistenNameIDFormat.setFormat(NameIDType.PERSISTENT); - - idpSSODescriptor.getNameIDFormats().add(persistenNameIDFormat); - - NameIDFormat transientNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - transientNameIDFormat.setFormat(NameIDType.TRANSIENT); - - idpSSODescriptor.getNameIDFormats().add(transientNameIDFormat); - - NameIDFormat unspecifiedNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); - unspecifiedNameIDFormat.setFormat(NameIDType.UNSPECIFIED); - - idpSSODescriptor.getNameIDFormats().add(unspecifiedNameIDFormat); - - return idpSSODescriptor; - - } - } 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 0c7502003..08d9f67b6 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 @@ -22,15 +22,11 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; +import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.xml.transform.TransformerException; import org.apache.commons.lang.StringEscapeUtils; import org.joda.time.DateTime; @@ -51,15 +47,15 @@ import org.opensaml.saml2.metadata.AttributeConsumingService; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.xml.io.MarshallingException; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.signature.SignableXMLObject; - -import java.util.Arrays; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; -import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; -import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.exception.InvalidProtocolRequestException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; @@ -67,21 +63,13 @@ import at.gv.egovernment.moa.id.auth.exception.ProtocolNotActiveException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; -import at.gv.egovernment.moa.id.moduls.IAction; -import at.gv.egovernment.moa.id.moduls.IModulInfo; import at.gv.egovernment.moa.id.moduls.IRequest; import at.gv.egovernment.moa.id.moduls.NoPassivAuthenticationException; -import at.gv.egovernment.moa.id.moduls.RequestImpl; -import at.gv.egovernment.moa.id.moduls.RequestStorage; -import at.gv.egovernment.moa.id.moduls.SSOManager; -import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IDecoder; +import at.gv.egovernment.moa.id.protocols.AbstractAuthProtocolModulController; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; -import at.gv.egovernment.moa.id.protocols.pvp2x.binding.SoapBinding; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; -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.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.SoapBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionValidationExeption; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AttributQueryException; @@ -92,19 +80,28 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NameIDFormatNotSuppor import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SLOException; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; +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.IDPCredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.CheckMandateAttributes; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.protocols.pvp2x.validation.AuthnRequestValidator; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.SAMLVerificationEngine; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; import at.gv.egovernment.moa.id.util.ErrorResponseUtils; +import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; import at.gv.egovernment.moa.id.util.VelocityLogAdapter; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; -public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { +@Controller +public class PVP2XProtocol extends AbstractAuthProtocolModulController { + @Autowired IDPCredentialProvider pvpCredentials; + @Autowired SAMLVerificationEngine samlVerificationEngine; + public static final String NAME = PVP2XProtocol.class.getName(); public static final String PATH = "id_pvp2x"; @@ -119,41 +116,15 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { public static final String ENDPOINT_SP = "sp"; public static final String PARAMETER_ENDPOINT = "endpointtype"; - - private static List<IDecoder> decoder = new ArrayList<IDecoder>(); - - private static HashMap<String, IAction> actions = new HashMap<String, IAction>(); - + public static final List<String> DEFAULTREQUESTEDATTRFORINTERFEDERATION = Arrays.asList( new String[] { PVPConstants.EID_SECTOR_FOR_IDENTIFIER_NAME }); - static { - decoder.add(new PostBinding()); - decoder.add(new RedirectBinding()); - decoder.add(new SoapBinding()); - - actions.put(REDIRECT, new AuthenticationAction()); - actions.put(POST, new AuthenticationAction()); - actions.put(METADATA, new MetadataAction()); - actions.put(ATTRIBUTEQUERY, new AttributQueryAction()); - actions.put(SINGLELOGOUT, new SingleLogOutAction()); - - //TODO: insert getArtifact action - - instance = new PVP2XProtocol(); - + static { new VelocityLogAdapter(); - } - - private static PVP2XProtocol instance = null; - - public static PVP2XProtocol getInstance() { - if (instance == null) { - instance = new PVP2XProtocol(); - } - return instance; + } public String getName() { @@ -163,162 +134,177 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { public String getPath() { return PATH; } - - private IDecoder findDecoder(String action, HttpServletRequest req) { - Iterator<IDecoder> decoderIT = decoder.iterator(); - while (decoderIT.hasNext()) { - IDecoder decoder = decoderIT.next(); - if (decoder.handleDecode(action, req)) { - return decoder; - } - } - - return null; - } - - private boolean isServiceProviderEndPointUsed(HttpServletRequest req) throws InvalidProtocolRequestException { - Object obj = req.getParameter(PARAMETER_ENDPOINT); - if (obj instanceof String) { - String param = (String) obj; - if (MiscUtil.isNotEmpty(param)) { - if (ENDPOINT_IDP.equals(param)) - return false; - - else if (ENDPOINT_SP.equals(param)) - return true; - } - } - - Logger.error("No valid PVP 2.1 entpoint descriptor"); - throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); - } public PVP2XProtocol() { super(); } - - public IRequest preProcess(HttpServletRequest request, - HttpServletResponse response, String action, - String sessionId, String transactionId) throws MOAIDException { - - if (!AuthConfigurationProviderFactory.getInstance().getAllowedProtocols().isPVP21Active()) { + //PVP2.x metadata end-point + @RequestMapping(value = "/pvp2/metadata", method = {RequestMethod.POST, RequestMethod.GET}) + public void PVPMetadataRequest(HttpServletRequest req, HttpServletResponse resp) throws MOAIDException { + if (!authConfig.getAllowedProtocols().isPVP21Active()) { Logger.info("PVP2.1 is deaktivated!"); throw new ProtocolNotActiveException("auth.22", new java.lang.Object[] { NAME }); } + //create pendingRequest object + PVPTargetConfiguration pendingReq = applicationContext.getBean(PVPTargetConfiguration.class); + pendingReq.initialize(req); + pendingReq.setModule(NAME); + + revisionsLogger.logEvent( + pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), + MOAIDEventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); + metadataAction.processRequest(pendingReq, + req, resp, null); - - if(METADATA.equals(action)) { - return new PVPTargetConfiguration(); + } + + //PVP2.x IDP POST-Binding end-point + @RequestMapping(value = "/pvp2/post", method = {RequestMethod.POST}) + public void PVPIDPPostRequest(HttpServletRequest req, HttpServletResponse resp) throws MOAIDException { + if (!authConfig.getAllowedProtocols().isPVP21Active()) { + Logger.info("PVP2.1 is deaktivated!"); + throw new ProtocolNotActiveException("auth.22", new java.lang.Object[] { NAME }); } - IDecoder decoder = findDecoder(action, request); - if (decoder == null) { - return null; + try { + //create pendingRequest object + PVPTargetConfiguration pendingReq = applicationContext.getBean(PVPTargetConfiguration.class); + pendingReq.initialize(req); + pendingReq.setModule(NAME); + + revisionsLogger.logEvent(MOAIDEventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); + revisionsLogger.logEvent(MOAIDEventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent( + pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), + MOAIDEventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + //get POST-Binding decoder implementation + InboundMessage msg = (InboundMessage) new PostBinding().decode(req, resp, false); + pendingReq.setRequest(msg); + + //preProcess Message + preProcess(req, resp, pendingReq); + + } catch (SecurityPolicyException e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + + } catch (SecurityException e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } catch (Throwable e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + + throw new MOAIDException(e.getMessage(), new Object[] {}); + } + } + + //PVP2.x IDP Redirect-Binding end-point + @RequestMapping(value = "/pvp2/redirect", method = {RequestMethod.GET}) + public void PVPIDPRedirecttRequest(HttpServletRequest req, HttpServletResponse resp) throws MOAIDException { + if (!AuthConfigurationProviderFactory.getInstance().getAllowedProtocols().isPVP21Active()) { + Logger.info("PVP2.1 is deaktivated!"); + throw new ProtocolNotActiveException("auth.22", new java.lang.Object[] { NAME }); + } + try { + //create pendingRequest object + PVPTargetConfiguration pendingReq = applicationContext.getBean(PVPTargetConfiguration.class); + pendingReq.initialize(req); + pendingReq.setModule(NAME); + + revisionsLogger.logEvent(MOAIDEventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); + revisionsLogger.logEvent(MOAIDEventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent( + pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), + MOAIDEventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + //get POST-Binding decoder implementation + InboundMessage msg = (InboundMessage) new RedirectBinding().decode(req, resp, false); + pendingReq.setRequest(msg); + + //preProcess Message + preProcess(req, resp, pendingReq); - InboundMessage msg = (InboundMessage) decoder.decode(request, response, isServiceProviderEndPointUsed(request)); + } catch (SecurityPolicyException e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + } catch (SecurityException e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } catch (Throwable e) { + String samlRequest = req.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID protocol request: " + samlRequest, e); + + throw new MOAIDException(e.getMessage(), new Object[] {}); + } + } + + + + + public void preProcess(HttpServletRequest request, + HttpServletResponse response, PVPTargetConfiguration pendingReq) throws Throwable { + + InboundMessage msg = pendingReq.getRequest(); + if (MiscUtil.isEmpty(msg.getEntityID())) { throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); } if(!msg.isVerified()) { - SAMLVerificationEngine engine = new SAMLVerificationEngine(); - engine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + samlVerificationEngine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine()); msg.setVerified(true); - + } if (msg instanceof MOARequest && ((MOARequest)msg).getSamlRequest() instanceof AuthnRequest) - return preProcessAuthRequest(request, response, (MOARequest) msg, sessionId, transactionId); + preProcessAuthRequest(request, response, pendingReq); else if (msg instanceof MOARequest && ((MOARequest)msg).getSamlRequest() instanceof AttributeQuery) - return preProcessAttributQueryRequest(request, response, (MOARequest) msg, sessionId, transactionId); + preProcessAttributQueryRequest(request, response, pendingReq); else if (msg instanceof MOARequest && ((MOARequest)msg).getSamlRequest() instanceof LogoutRequest) - return preProcessLogOut(request, response, msg, sessionId, transactionId); + preProcessLogOut(request, response, pendingReq); else if (msg instanceof MOAResponse && ((MOAResponse)msg).getResponse() instanceof LogoutResponse) - return preProcessLogOut(request, response, msg, sessionId, transactionId); - - else if (msg instanceof MOAResponse && - ((MOAResponse)msg).getResponse() instanceof Response) { - //load service provider AuthRequest from session - - IRequest obj = RequestStorage.getPendingRequest(msg.getRelayState()); - if (obj instanceof RequestImpl) { - RequestImpl iReqSP = (RequestImpl) obj; - - MOAReversionLogger.getInstance().logEvent(iReqSP, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHRESPONSE); - - MOAResponse processedMsg = preProcessAuthResponse((MOAResponse) msg); - - if ( processedMsg != null ) { - iReqSP.setInterfederationResponse(processedMsg); - - MOAReversionLogger.getInstance().logEvent(iReqSP, MOAIDEventConstants.AUTHPROCESS_INTERFEDERATION_REVEIVED); - - Logger.info("Receive a valid assertion from IDP " + msg.getEntityID() - + ". Switch to original transaction with ID " + iReqSP.getRequestID()); - TransactionIDUtils.setTransactionId(iReqSP.getRequestID()); - TransactionIDUtils.setSessionId(iReqSP.getSessionIdentifier()); - - } else { - Logger.info("Interfederated IDP " + msg.getEntityID() + " has NO valid SSO session." - +". Switch back local authentication process ..."); - - SSOManager ssomanager = SSOManager.getInstance(); - ssomanager.removeInterfederatedSSOIDP(msg.getEntityID(), request); - - iReqSP.setRequestedIDP(null); - - } - - return iReqSP; - - } - - Logger.error("Stored PVP21 authrequest from service provider has an unsuppored type."); - return null; - - } else { + preProcessLogOut(request, response, pendingReq); + + else { Logger.error("Receive unsupported PVP21 message"); throw new MOAIDException("Unsupported PVP21 message", new Object[] {}); } - } catch (PVP2Exception e) { - throw e; - - } catch (SecurityPolicyException e) { - String samlRequest = request.getParameter("SAMLRequest"); - Logger.warn("Receive INVALID protocol request: " + samlRequest, e); - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - - } catch (SecurityException e) { - String samlRequest = request.getParameter("SAMLRequest"); - Logger.warn("Receive INVALID protocol request: " + samlRequest, e); - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); - - } catch (InvalidProtocolRequestException e) { - String samlRequest = request.getParameter("SAMLRequest"); - Logger.warn("Receive INVALID protocol request: " + samlRequest, e); - throw e; + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), + pendingReq, MOAIDEventConstants.AUTHPROTOCOL_TYPE, PATH); - } catch (Throwable e) { - String samlRequest = request.getParameter("SAMLRequest"); - Logger.warn("Receive INVALID protocol request: " + samlRequest, e); - - throw new MOAIDException(e.getMessage(), new Object[] {}); - } + //switch to session authentication + performAuthentication(request, response, pendingReq); } public boolean generateErrorMessage(Throwable e, @@ -387,7 +373,7 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { samlResponse.setIssueInstant(new DateTime()); Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); - nissuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + nissuer.setValue(pvpRequest.getAuthURLWithOutSlash()); nissuer.setFormat(NameID.ENTITY); samlResponse.setIssuer(nissuer); @@ -395,11 +381,7 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { encoder = new RedirectBinding(); - - } else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_ARTIFACT_BINDING_URI)) { - // TODO: not supported YET!! - //binding = new ArtifactBinding(); - + } else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { encoder = new PostBinding(); @@ -416,31 +398,13 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { if (pvpRequest.getRequest() != null) relayState = pvpRequest.getRequest().getRelayState(); + X509Credential signCred = pvpCredentials.getIDPAssertionSigningCredential(); + encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerURL(), - relayState); + relayState, signCred); return true; } - public IAction getAction(String action) { - return actions.get(action); - } - - public IAction canHandleRequest(HttpServletRequest request, - HttpServletResponse response) { - if(request.getParameter("SAMLRequest") != null && request.getMethod().equals("GET")) { - return getAction(REDIRECT); - - } else if(request.getParameter("SAMLRequest") != null && request.getMethod().equals("POST")) { - return getAction(POST); - - } - - if(METADATA.equals(request.getParameter("action"))) { - return getAction(METADATA); - } - return null; - } - public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { @@ -456,12 +420,10 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { * @return * @throws MOAIDException */ - private IRequest preProcessLogOut(HttpServletRequest request, - HttpServletResponse response, InboundMessage inMsg, - String sessionId, String transactionId) throws MOAIDException { + private void preProcessLogOut(HttpServletRequest request, + HttpServletResponse response, PVPTargetConfiguration pendingReq) throws MOAIDException { - PVPTargetConfiguration config = new PVPTargetConfiguration(); - + InboundMessage inMsg = pendingReq.getRequest(); MOARequest msg; if (inMsg instanceof MOARequest && ((MOARequest)inMsg).getSamlRequest() instanceof LogoutRequest) { @@ -480,11 +442,11 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { Logger.info("Dispatch PVP2 SingleLogOut: OAURL=" + oaURL + " Binding=" + msg.getRequestBinding()); - config.setOAURL(oaURL); - config.setOnlineApplicationConfiguration(oa); - config.setBinding(msg.getRequestBinding()); + pendingReq.setOAURL(oaURL); + pendingReq.setOnlineApplicationConfiguration(oa); + pendingReq.setBinding(msg.getRequestBinding()); - MOAReversionLogger.getInstance().logEvent(sessionId, transactionId, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_SLO); + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_SLO); @@ -496,13 +458,24 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { Logger.debug("PreProcess SLO Response from " + resp.getIssuer()); - if (!resp.getDestination().startsWith( - PVPConfiguration.getInstance().getIDPPublicPath())) { + List<String> allowedPublicURLPrefix = + AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix(); + boolean isAllowedDestination = false; + + for (String prefix : allowedPublicURLPrefix) { + if (!resp.getDestination().startsWith( + prefix)) { + isAllowedDestination = true; + break; + } + } + + if (!isAllowedDestination) { Logger.warn("PVP 2.1 single logout response destination does not match to IDP URL"); throw new AssertionValidationExeption("PVP 2.1 single logout response destination does not match to IDP URL", null); } - + //TODO: check if relayState exists inMsg.getRelayState(); @@ -511,29 +484,32 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { throw new MOAIDException("Unsupported request", new Object[] {}); - config.setRequest(inMsg); - config.setAction(SINGLELOGOUT); - return config; + pendingReq.setRequest(inMsg); + pendingReq.setAction(SINGLELOGOUT); + + //Single LogOut Request needs no authentication + pendingReq.setNeedAuthentication(false); + + //set protocol action, which should be executed + pendingReq.setAction(SingleLogOutAction.class.getName()); } /** * PreProcess AttributeQuery request * @param request * @param response - * @param moaRequest - * @return + * @param pendingReq * @throws Throwable */ - private IRequest preProcessAttributQueryRequest(HttpServletRequest request, - HttpServletResponse response, MOARequest moaRequest, - String sessionId, String transactionId) throws Throwable { - + private void preProcessAttributQueryRequest(HttpServletRequest request, + HttpServletResponse response, PVPTargetConfiguration pendingReq) throws Throwable { + MOARequest moaRequest = ((MOARequest)pendingReq.getRequest()); AttributeQuery attrQuery = (AttributeQuery) moaRequest.getSamlRequest(); moaRequest.setEntityID(attrQuery.getIssuer().getValue()); //validate destination String destinaten = attrQuery.getDestination(); - if (!PVPConfiguration.getInstance().getIDPAttributeQueryService().equals(destinaten)) { + if (!PVPConfiguration.getInstance().getIDPAttributeQueryService(HTTPUtils.extractAuthURLFromRequest(request)).equals(destinaten)) { Logger.warn("AttributeQuery destination does not match IDP AttributeQueryService URL"); throw new AttributQueryException("AttributeQuery destination does not match IDP AttributeQueryService URL", null); @@ -558,35 +534,40 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { } - PVPTargetConfiguration config = new PVPTargetConfiguration(); - config.setRequest(moaRequest); - config.setOAURL(moaRequest.getEntityID()); - config.setOnlineApplicationConfiguration(oa); - config.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); + pendingReq.setRequest(moaRequest); + pendingReq.setOAURL(moaRequest.getEntityID()); + pendingReq.setOnlineApplicationConfiguration(oa); + pendingReq.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); + + //Attribute-Query Request needs authentication + pendingReq.setNeedAuthentication(true); + + //set protocol action, which should be executed after authentication + pendingReq.setAction(AttributQueryAction.class.getName()); + + //write revisionslog entry + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_ATTRIBUTQUERY); - MOAReversionLogger.getInstance().logEvent(sessionId, transactionId, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_ATTRIBUTQUERY); - return config; } /** * PreProcess Authn request * @param request * @param response - * @param moaRequest - * @return + * @param pendingReq * @throws Throwable */ - private IRequest preProcessAuthRequest(HttpServletRequest request, - HttpServletResponse response, MOARequest moaRequest, - String sessionId, String transactionId) throws Throwable { - + private void preProcessAuthRequest(HttpServletRequest request, + HttpServletResponse response, PVPTargetConfiguration pendingReq) throws Throwable { + + MOARequest moaRequest = ((MOARequest)pendingReq.getRequest()); SignableXMLObject samlReq = moaRequest.getSamlRequest(); if(!(samlReq instanceof AuthnRequest)) { throw new MOAIDException("Unsupported request", new Object[] {}); } - + EntityDescriptor metadata = moaRequest.getEntityMetadata(); if(metadata == null) { throw new NoMetadataInformationException(); @@ -611,10 +592,25 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { AssertionConsumerService consumerService = null; if (MiscUtil.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) && MiscUtil.isNotEmpty(authnRequest.getProtocolBinding())) { - //use AssertionConsumerServiceURL from request - consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); - consumerService.setBinding(authnRequest.getProtocolBinding()); - consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL()); + //use AssertionConsumerServiceURL from request + + //check requested AssertionConsumingService URL against metadata + List<AssertionConsumerService> metadataAssertionServiceList = spSSODescriptor.getAssertionConsumerServices(); + for (AssertionConsumerService service : metadataAssertionServiceList) { + if (authnRequest.getProtocolBinding().equals(service.getBinding()) + && authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { + consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); + consumerService.setBinding(authnRequest.getProtocolBinding()); + consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL()); + Logger.debug("Requested AssertionConsumerServiceURL is valid."); + } + } + + if (consumerService == null) { + throw new InvalidAssertionConsumerServiceException(authnRequest.getAssertionConsumerServiceURL()); + + } + } else { //use AssertionConsumerServiceIndex and select consumerService from metadata @@ -633,9 +629,10 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { if (consumerService == null) { throw new InvalidAssertionConsumerServiceException(aIdx); - } + } } + //select AttributeConsumingService from request AttributeConsumingService attributeConsumer = null; Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); @@ -669,59 +666,24 @@ public class PVP2XProtocol extends MOAIDAuthConstants implements IModulInfo { Logger.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding()); - PVPTargetConfiguration config = new PVPTargetConfiguration(); - config.setOAURL(oaURL); - config.setOnlineApplicationConfiguration(oa); - config.setBinding(consumerService.getBinding()); - config.setRequest(moaRequest); - config.setConsumerURL(consumerService.getLocation()); + pendingReq.setOAURL(oaURL); + pendingReq.setOnlineApplicationConfiguration(oa); + pendingReq.setBinding(consumerService.getBinding()); + pendingReq.setRequest(moaRequest); + pendingReq.setConsumerURL(consumerService.getLocation()); //parse AuthRequest - config.setPassiv(authReq.isPassive()); - config.setForce(authReq.isForceAuthn()); + pendingReq.setPassiv(authReq.isPassive()); + pendingReq.setForce(authReq.isForceAuthn()); + //AuthnRequest needs authentication + pendingReq.setNeedAuthentication(true); - MOAReversionLogger.getInstance().logEvent(sessionId, transactionId, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST); + //set protocol action, which should be executed after authentication + pendingReq.setAction(AuthenticationAction.class.getName()); - return config; - } - - /** - * PreProcess AuthResponse and Assertion - * @param msg - */ - private MOAResponse preProcessAuthResponse(MOAResponse msg) { - Logger.debug("Start PVP21 assertion processing... "); - Response samlResp = (Response) msg.getResponse(); - - try { - if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { - - //validate PVP 2.1 assertion - SAMLVerificationEngine.validateAssertion(samlResp, true); - - msg.setSAMLMessage(SAML2Utils.asDOMDocument(samlResp).getDocumentElement()); - return msg; - - } else { - Logger.debug("Receive StatusCode " + samlResp.getStatus().getStatusCode().getValue() - + " from interfederated IDP."); - - } - - } catch (IOException e) { - Logger.warn("Interfederation response marshaling FAILED.", e); - - } catch (MarshallingException e) { - Logger.warn("Interfederation response marshaling FAILED.", e); - - } catch (TransformerException e) { - Logger.warn("Interfederation response marshaling FAILED.", e); - - } catch (AssertionValidationExeption e) { - //error is already logged, to nothing - } + //write revisionslog entry + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST); - return null; } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPAssertionStorage.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPAssertionStorage.java index 5062646b6..0dd309154 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPAssertionStorage.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPAssertionStorage.java @@ -25,27 +25,20 @@ package at.gv.egovernment.moa.id.protocols.pvp2x; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.artifact.SAMLArtifactMap; import org.opensaml.xml.io.MarshallingException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.StoredAssertion; -import at.gv.egovernment.moa.id.storage.AssertionStorage; +import at.gv.egovernment.moa.id.storage.ITransactionStorage; +@Service("PVPAssertionStorage") public class PVPAssertionStorage implements SAMLArtifactMap { - - private static PVPAssertionStorage instance = null; - - public static PVPAssertionStorage getInstance() { - if(instance == null) { - instance = new PVPAssertionStorage(); - } - return instance; - } - - //private Map<String, SAMLArtifactMapEntry> assertions = new HashMap<String, SAMLArtifactMapEntry>(); - private AssertionStorage assertions = AssertionStorage.getInstance(); + @Autowired private ITransactionStorage transactionStorage; + public boolean contains(String artifact) { - return assertions.containsKey(artifact); + return transactionStorage.containsKey(artifact); } public void put(String artifact, String relyingPartyId, String issuerId, @@ -56,7 +49,7 @@ public class PVPAssertionStorage implements SAMLArtifactMap { samlMessage); try { - assertions.put(artifact, assertion); + transactionStorage.put(artifact, assertion); } catch (MOADatabaseException e) { // TODO Insert Error Handling, if Assertion could not be stored @@ -66,7 +59,7 @@ public class PVPAssertionStorage implements SAMLArtifactMap { public SAMLArtifactMapEntry get(String artifact) { try { - return assertions.get(artifact, SAMLArtifactMapEntry.class); + return transactionStorage.get(artifact, SAMLArtifactMapEntry.class); } catch (MOADatabaseException e) { // TODO Insert Error Handling, if Assertion could not be read @@ -76,7 +69,7 @@ public class PVPAssertionStorage implements SAMLArtifactMap { } public void remove(String artifact) { - assertions.remove(artifact); + transactionStorage.remove(artifact); } } 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 74b20356e..27773a248 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 @@ -22,28 +22,28 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Attribute; import org.opensaml.saml2.core.impl.AuthnRequestImpl; import org.opensaml.saml2.metadata.AttributeConsumingService; import org.opensaml.saml2.metadata.RequestedAttribute; import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; -import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; -import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.moduls.RequestImpl; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AttributQueryBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; 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.logging.Logger; +@Component("PVPTargetConfiguration") +@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) public class PVPTargetConfiguration extends RequestImpl { private static final long serialVersionUID = 4889919265919638188L; @@ -81,15 +81,13 @@ public class PVPTargetConfiguration extends RequestImpl { * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes() */ @Override - public List<Attribute> getRequestedAttributes() { + public Collection<String> getRequestedAttributes() { Map<String, String> reqAttr = new HashMap<String, String>(); for (String el : PVP2XProtocol.DEFAULTREQUESTEDATTRFORINTERFEDERATION) reqAttr.put(el, ""); - try { - OAAuthParameter oa = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(getOAURL()); - + try { SPSSODescriptor spSSODescriptor = getRequest().getEntityMetadata().getSPSSODescriptor(SAMLConstants.SAML20P_NS); if (spSSODescriptor.getAttributeConsumingServices() != null && spSSODescriptor.getAttributeConsumingServices().size() > 0) { @@ -125,15 +123,13 @@ public class PVPTargetConfiguration extends RequestImpl { reqAttr.put(attr.getName(), ""); } - return AttributQueryBuilder.buildSAML2AttributeList(oa, reqAttr.keySet().iterator()); + //return attributQueryBuilder.buildSAML2AttributeList(this.getOnlineApplicationConfiguration(), reqAttr.keySet().iterator()); + return reqAttr.keySet(); } catch (NoMetadataInformationException e) { Logger.warn("NO metadata found for Entity " + getRequest().getEntityID()); return null; - } catch (ConfigurationException e) { - Logger.error("Load configuration for OA " + getOAURL() + " FAILED", e); - return null; } } 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 b567798fa..5afa10a72 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 @@ -23,42 +23,22 @@ 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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; @@ -67,35 +47,23 @@ 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.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.ISLOInformationContainer; 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; 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.storage.IAuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.storage.ITransactionStorage; 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; @@ -103,8 +71,16 @@ import at.gv.egovernment.moa.util.URLEncoder; * @author tlenz * */ +@Service("pvpSingleLogOutService") public class SingleLogOutAction implements IAction { + @Autowired private SSOManager ssomanager; + @Autowired private AuthenticationManager authManager; + @Autowired private IAuthenticationSessionStoreage authenticationSessionStorage; + @Autowired private ITransactionStorage transactionStorage; + @Autowired private SingleLogOutBuilder sloBuilder; + + /* (non-Javadoc) * @see at.gv.egovernment.moa.id.moduls.IAction#processRequest(at.gv.egovernment.moa.id.moduls.IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.data.IAuthData) */ @@ -122,7 +98,7 @@ public class SingleLogOutAction implements IAction { LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); AuthenticationSession session = - AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID( + authenticationSessionStorage.searchMOASessionWithNameIDandOAID( logOutReq.getIssuer().getValue(), logOutReq.getNameID().getValue()); @@ -131,36 +107,34 @@ public class SingleLogOutAction implements IAction { + logOutReq.getNameID().getValue() + " and OA " + logOutReq.getIssuer().getValue()); Logger.info("Search active SSO session with SSO session cookie"); - SSOManager ssomanager = SSOManager.getInstance(); String ssoID = ssomanager.getSSOSessionID(httpReq); if (MiscUtil.isEmpty(ssoID)) { - Logger.warn("Can not find active Session. Single LogOut not possible!"); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - //LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq, StatusCode.RESPONDER_URI); - LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, null); + Logger.info("Can not find active Session. Single LogOut not possible!"); + SingleLogoutService sloService = sloBuilder.getResponseSLODescriptor(pvpReq); + //LogoutResponse message = sloBuilder.buildSLOErrorResponse(sloService, pvpReq, StatusCode.RESPONDER_URI); + LogoutResponse message = sloBuilder.buildSLOResponseMessage(sloService, pvpReq, null); Logger.info("Sending SLO success message to requester ..."); - SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + sloBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } else { String moasession = ssomanager.getMOASession(ssoID); try { - session = AuthenticationSessionStoreage.getSession(moasession); + session = authenticationSessionStorage.getSession(moasession); } catch (MOADatabaseException e) { - Logger.warn("Can not find active Session. Single LogOut not possible!"); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - //LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq, StatusCode.RESPONDER_URI); - LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, null); + Logger.info("Can not find active Session. Single LogOut not possible!"); + SingleLogoutService sloService = sloBuilder.getResponseSLODescriptor(pvpReq); + //LogoutResponse message = sloBuilder.buildSLOErrorResponse(sloService, pvpReq, StatusCode.RESPONDER_URI); + LogoutResponse message = sloBuilder.buildSLOResponseMessage(sloService, pvpReq, null); Logger.info("Sending SLO success message to requester ..."); - SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + sloBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } } } - - AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.performSingleLogOut(httpReq, httpResp, session, pvpReq); } else if (pvpReq.getRequest() instanceof MOAResponse && @@ -204,10 +178,10 @@ public class SingleLogOutAction implements IAction { Object data = SerializationUtils.deserialize(element.getAssertion()); if (data instanceof SLOInformationContainer) { - SLOInformationContainer sloContainer = (SLOInformationContainer) data; + ISLOInformationContainer sloContainer = (ISLOInformationContainer) data; //check status - SingleLogOutBuilder.checkStatusCode(sloContainer, logOutResp); + sloBuilder.checkStatusCode(sloContainer, logOutResp); if (sloContainer.hasFrontChannelOA()) { try { @@ -253,13 +227,13 @@ public class SingleLogOutAction implements IAction { 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()); + SingleLogoutService sloService = sloBuilder.getResponseSLODescriptor(sloContainer.getSloRequest()); + LogoutResponse message = sloBuilder.buildSLOResponseMessage(sloService, sloContainer.getSloRequest(), sloContainer.getSloFailedOAs()); + redirectURL = sloBuilder.getFrontChannelSLOMessageURL(sloService, message, httpReq, httpResp, sloContainer.getSloRequest().getRequest().getRelayState()); } else { //print SLO information directly - redirectURL = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/idpSingleLogout"; + redirectURL = req.getAuthURL() + "/idpSingleLogout"; String artifact = Random.nextRandom(); @@ -270,12 +244,12 @@ public class SingleLogOutAction implements IAction { else statusCode = MOAIDAuthConstants.SLOSTATUS_ERROR; - AssertionStorage.getInstance().put(artifact, statusCode); + transactionStorage.put(artifact, statusCode); redirectURL = addURLParameter(redirectURL, MOAIDAuthConstants.PARAM_SLOSTATUS, artifact); } //redirect to Redirect Servlet - String url = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/RedirectServlet"; + String url = req.getAuthURL() + "/RedirectServlet"; url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(redirectURL, "UTF-8")); url = httpResp.encodeRedirectURL(url); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java deleted file mode 100644 index 4d353ffcd..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.protocols.pvp2x.binding; - -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.common.xml.SAMLConstants; -import org.opensaml.saml2.binding.encoding.HTTPArtifactEncoder; -import org.opensaml.saml2.core.RequestAbstractType; -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.HttpServletResponseAdapter; -import org.opensaml.xml.security.SecurityException; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.signature.Signature; - -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPAssertionStorage; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; - -public class ArtifactBinding implements IDecoder, IEncoder { - - public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request, String targetLocation, String relayState) - throws MessageEncodingException, SecurityException { - - } - - public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - StatusResponseType response, String targetLocation, String relayState) - throws MessageEncodingException, SecurityException { - try { - Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); - - Signature signer = CredentialProvider.getIDPSignature(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(); - - HTTPArtifactEncoder encoder = new HTTPArtifactEncoder(engine, - "resources/templates/pvp_postbinding_template.html", - PVPAssertionStorage.getInstance()); - - encoder.setPostEncoding(false); - HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( - resp, true); - BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); - SingleSignOnService service = new SingleSignOnServiceBuilder() - .buildObject(); - service.setBinding(SAMLConstants.SAML2_ARTIFACT_BINDING_URI); - service.setLocation(targetLocation); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setPeerEntityEndpoint(service); - context.setOutboundSAMLMessage(response); - context.setOutboundMessageTransport(responseAdapter); - - encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); - - } catch (Exception e) { - throw new SecurityException(e); - } - } - - public InboundMessageInterface decode(HttpServletRequest req, - HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, - SecurityException { - - return null; - } - - - public boolean handleDecode(String action, HttpServletRequest req) { - - return false; - } - - public String getSAML2BindingName() { - return SAMLConstants.SAML2_ARTIFACT_BINDING_URI; - } - -} 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 de5548a44..3b2fb3687 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 @@ -29,24 +29,40 @@ import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; public interface IEncoder { + + /** + * + * @param req The http request + * @param resp The http response + * @param request The SAML2 request object + * @param targetLocation URL, where the request should be transmit + * @param relayState token for session handling + * @param credentials Credential to sign the request object + * @throws MessageEncodingException + * @throws SecurityException + * @throws PVP2Exception + */ public void encodeRequest(HttpServletRequest req, - HttpServletResponse resp, RequestAbstractType request, String targetLocation, String relayState) + HttpServletResponse resp, RequestAbstractType request, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException, PVP2Exception; /** * Encoder SAML Response * @param req The http request * @param resp The http response - * @param response The repsonse object - * @param targetLocation + * @param response The SAML2 repsonse object + * @param targetLocation URL, where the request should be transmit + * @param relayState token for session handling + * @param credentials Credential to sign the response object * @throws MessageEncodingException * @throws SecurityException */ public void encodeRespone(HttpServletRequest req, - HttpServletResponse resp, StatusResponseType response, String targetLocation, String relayState) + HttpServletResponse resp, StatusResponseType response, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException, PVP2Exception; } 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 65400444d..ebb4b2991 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 @@ -28,53 +28,51 @@ import javax.servlet.http.HttpServletResponse; import org.apache.velocity.app.VelocityEngine; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; -import org.opensaml.common.binding.SAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; import org.opensaml.saml2.core.RequestAbstractType; -import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.IDPSSODescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.SingleLogoutService; 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.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.Credential; -import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; -import org.opensaml.xml.security.x509.X509Credential; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; import at.gv.egovernment.moa.id.protocols.pvp2x.config.MOADefaultBootstrap; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface; 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.metadata.MOAMetadataProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.validation.MOAPVPSignedRequestPolicyRule; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; +import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; public class PostBinding implements IDecoder, IEncoder { - + public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request, String targetLocation, String relayState) + RequestAbstractType request, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException { try { - X509Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); +// X509Credential credentials = credentialProvider +// .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); @@ -97,9 +95,9 @@ public class PostBinding implements IDecoder, IEncoder { encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); +// } catch (CredentialsNotAvailableException e) { +// e.printStackTrace(); +// throw new SecurityException(e); } catch (Exception e) { e.printStackTrace(); throw new SecurityException(e); @@ -107,12 +105,12 @@ public class PostBinding implements IDecoder, IEncoder { } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - StatusResponseType response, String targetLocation, String relayState) + StatusResponseType response, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException { try { - X509Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); +// X509Credential credentials = credentialProvider +// .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); @@ -138,9 +136,9 @@ public class PostBinding implements IDecoder, IEncoder { context.setRelayState(relayState); encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); +// } catch (CredentialsNotAvailableException e) { +// e.printStackTrace(); +// throw new SecurityException(e); } catch (Exception e) { e.printStackTrace(); throw new SecurityException(e); @@ -159,11 +157,11 @@ public class PostBinding implements IDecoder, IEncoder { //set metadata descriptor type if (isSPEndPoint) { messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getSPSSOPostService())); + decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getSPSSOPostService(HTTPUtils.extractAuthURLFromRequest(req)))); } else { messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getIDPSSOPostService())); + decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getIDPSSOPostService(HTTPUtils.extractAuthURLFromRequest(req)))); } } catch (ConfigurationException e) { @@ -171,7 +169,16 @@ public class PostBinding implements IDecoder, IEncoder { } messageContext.setMetadataProvider(MOAMetadataProvider.getInstance()); - + + //set security policy context + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add( + new MOAPVPSignedRequestPolicyRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine(), + messageContext.getPeerEntityRole())); + SecurityPolicyResolver secResolver = new StaticSecurityPolicyResolver(policy); + messageContext.setSecurityPolicyResolver(secResolver); + decode.decode(messageContext); InboundMessage msg = null; @@ -197,8 +204,9 @@ public class PostBinding implements IDecoder, IEncoder { if (MiscUtil.isEmpty(msg.getEntityID())) Logger.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer()); } - - msg.setVerified(false); + + + msg.setVerified(true); msg.setRelayState(messageContext.getRelayState()); return msg; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java index 9a505a7b0..0ff18d903 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 @@ -27,7 +27,6 @@ import javax.servlet.http.HttpServletResponse; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; -import org.opensaml.common.binding.SAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder; import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; @@ -48,7 +47,7 @@ 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.x509.X509Credential; +import org.opensaml.xml.security.credential.Credential; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; @@ -59,21 +58,20 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface 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.metadata.MOAMetadataProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; +import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; public class RedirectBinding implements IDecoder, IEncoder { - + public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request, String targetLocation, String relayState) + RequestAbstractType request, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException { - try { - X509Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); +// try { +// X509Credential credentials = credentialProvider +// .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); @@ -95,18 +93,18 @@ public class RedirectBinding implements IDecoder, IEncoder { context.setRelayState(relayState); encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); - } +// } catch (CredentialsNotAvailableException e) { +// e.printStackTrace(); +// throw new SecurityException(e); +// } } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - StatusResponseType response, String targetLocation, String relayState) - throws MessageEncodingException, SecurityException { - try { - X509Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); + StatusResponseType response, String targetLocation, String relayState, + Credential credentials) throws MessageEncodingException, SecurityException { +// try { +// X509Credential credentials = credentialProvider +// .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); @@ -128,10 +126,10 @@ public class RedirectBinding implements IDecoder, IEncoder { context.setRelayState(relayState); encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); - } +// } catch (CredentialsNotAvailableException e) { +// e.printStackTrace(); +// throw new SecurityException(e); +// } } public InboundMessageInterface decode(HttpServletRequest req, @@ -149,11 +147,11 @@ public class RedirectBinding implements IDecoder, IEncoder { //set metadata descriptor type if (isSPEndPoint) { messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getSPSSORedirectService())); + decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getSPSSORedirectService(HTTPUtils.extractAuthURLFromRequest(req)))); } else { messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getIDPSSORedirectService())); + decode.setURIComparator(new MOAURICompare(PVPConfiguration.getInstance().getIDPSSORedirectService(HTTPUtils.extractAuthURLFromRequest(req)))); } } catch (ConfigurationException e) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java index fee508d33..cc3553551 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java @@ -29,7 +29,6 @@ import javax.servlet.http.HttpServletResponse; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; -import org.opensaml.common.binding.SAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.encoding.HTTPSOAP11Encoder; import org.opensaml.saml2.core.RequestAbstractType; @@ -37,7 +36,6 @@ import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.ws.message.decoder.MessageDecodingException; import org.opensaml.ws.message.encoder.MessageEncodingException; -import org.opensaml.ws.soap.client.BasicSOAPMessageContext; import org.opensaml.ws.soap.soap11.Envelope; import org.opensaml.ws.soap.soap11.decoder.http.HTTPSOAP11Decoder; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; @@ -47,22 +45,23 @@ import org.opensaml.xml.parse.BasicParserPool; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.signature.SignableXMLObject; +import org.springframework.beans.factory.annotation.Autowired; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; import at.gv.egovernment.moa.id.protocols.pvp2x.config.MOADefaultBootstrap; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AttributQueryException; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; public class SoapBinding implements IDecoder, IEncoder { + @Autowired private IDPCredentialProvider credentialProvider; + public InboundMessageInterface decode(HttpServletRequest req, HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException, SecurityException, PVP2Exception { @@ -72,9 +71,23 @@ public class SoapBinding implements IDecoder, IEncoder { messageContext .setInboundMessageTransport(new HttpServletRequestAdapter( req)); - //messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); messageContext.setMetadataProvider(MOAMetadataProvider.getInstance()); - + + //TODO: update in a futher version: + // requires a special SignedSOAPRequestPolicyRole because + // messageContext.getInboundMessage() is not directly signed + + //set security context +// BasicSecurityPolicy policy = new BasicSecurityPolicy(); +// policy.getPolicyRules().add( +// new MOAPVPSignedRequestPolicyRule( +// TrustEngineFactory.getSignatureKnownKeysTrustEngine(), +// SPSSODescriptor.DEFAULT_ELEMENT_NAME)); +// SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( +// policy); +// messageContext.setSecurityPolicyResolver(resolver); + + //decode message soapDecoder.decode(messageContext); Envelope inboundMessage = (Envelope) messageContext @@ -120,17 +133,17 @@ public class SoapBinding implements IDecoder, IEncoder { } public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request, String targetLocation, String relayState) + RequestAbstractType request, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException, PVP2Exception { } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - StatusResponseType response, String targetLocation, String relayState) + StatusResponseType response, String targetLocation, String relayState, Credential credentials) throws MessageEncodingException, SecurityException, PVP2Exception { - try { - Credential credentials = CredentialProvider - .getIDPAssertionSigningCredential(); +// try { +// Credential credentials = credentialProvider +// .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); @@ -144,10 +157,10 @@ public class SoapBinding implements IDecoder, IEncoder { context.setOutboundMessageTransport(responseAdapter); encoder.encode(context); - } catch (CredentialsNotAvailableException e) { - e.printStackTrace(); - throw new SecurityException(e); - } +// } catch (CredentialsNotAvailableException e) { +// e.printStackTrace(); +// throw new SecurityException(e); +// } } public String getSAML2BindingName() { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AttributQueryBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AttributQueryBuilder.java index 91888df5c..9c097780b 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AttributQueryBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AttributQueryBuilder.java @@ -25,7 +25,6 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.builder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -46,17 +45,18 @@ import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.SignatureConstants; import org.opensaml.xml.signature.SignatureException; import org.opensaml.xml.signature.Signer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import org.w3c.dom.Document; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; -import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.SamlAttributeGenerator; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AttributQueryException; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Constants; @@ -65,9 +65,12 @@ import at.gv.egovernment.moa.util.Constants; * @author tlenz * */ +@Service("AttributQueryBuilder") public class AttributQueryBuilder { - public static List<Attribute> buildSAML2AttributeList(IOAAuthParameters oa, Iterator<String> iterator) { + @Autowired IDPCredentialProvider credentialProvider; + + public List<Attribute> buildSAML2AttributeList(IOAAuthParameters oa, Iterator<String> iterator) { Logger.debug("Build OA specific Attributes for AttributQuery request"); @@ -103,7 +106,7 @@ public class AttributQueryBuilder { } - public static AttributeQuery buildAttributQueryRequest(String nameID, + public AttributeQuery buildAttributQueryRequest(String nameID, String endpoint, List<Attribute> requestedAttributes) throws AttributQueryException { @@ -127,7 +130,7 @@ public class AttributQueryBuilder { query.setIssueInstant(now); Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); - nissuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + nissuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath().get(0)); nissuer.setFormat(NameID.ENTITY); query.setIssuer(nissuer); @@ -136,7 +139,7 @@ public class AttributQueryBuilder { query.setDestination(endpoint); - X509Credential idpSigningCredential = CredentialProvider.getIDPAssertionSigningCredential(); + X509Credential idpSigningCredential = credentialProvider.getIDPAssertionSigningCredential(); Signature signer = SAML2Utils.createSAMLObject(Signature.class); signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AuthResponseBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AuthResponseBuilder.java index 4959df16c..24c2626e3 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AuthResponseBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/AuthResponseBuilder.java @@ -66,13 +66,15 @@ import at.gv.egovernment.moa.logging.Logger; */ public class AuthResponseBuilder { - public static Response buildResponse(RequestAbstractType req, DateTime date, Assertion assertion) throws InvalidAssertionEncryptionException, ConfigurationException { + public static Response buildResponse(String authURL, RequestAbstractType req, DateTime date, Assertion assertion) throws InvalidAssertionEncryptionException, ConfigurationException { Response authResponse = SAML2Utils.createSAMLObject(Response.class); Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); //change to entity value from entity name to IDP EntityID (URL) - nissuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + if (authURL.endsWith("/")) + authURL = authURL.substring(0, authURL.length()-1); + nissuer.setValue(authURL); nissuer.setFormat(NameID.ENTITY); authResponse.setIssuer(nissuer); authResponse.setInResponseTo(req.getID()); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPAuthnRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPAuthnRequestBuilder.java new file mode 100644 index 000000000..312bb823d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPAuthnRequestBuilder.java @@ -0,0 +1,172 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.builder; + +import java.security.NoSuchAlgorithmException; + +import javax.servlet.http.HttpServletResponse; + +import org.joda.time.DateTime; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameIDPolicy; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.springframework.stereotype.Service; + +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AuthnRequestBuildException; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +@Service("PVPAuthnRequestBuilder") +public class PVPAuthnRequestBuilder { + + + /** + * Build a PVP2.x specific authentication request + * + * @param pendingReq Currently processed pendingRequest + * @param config AuthnRequest builder configuration, never null + * @param idpEntity SAML2 EntityDescriptor of the IDP, which receive this AuthnRequest, never null + * @param httpResp + * @throws NoSuchAlgorithmException + * @throws SecurityException + * @throws PVP2Exception + * @throws MessageEncodingException + */ + public void buildAuthnRequest(IRequest pendingReq, IPVPAuthnRequestBuilderConfiguruation config, + HttpServletResponse httpResp) throws NoSuchAlgorithmException, MessageEncodingException, PVP2Exception, SecurityException { + //get IDP Entity element from config + EntityDescriptor idpEntity = config.getIDPEntityDescriptor(); + + AuthnRequest authReq = SAML2Utils + .createSAMLObject(AuthnRequest.class); + + //select SingleSignOn Service endpoint from IDP metadata + SingleSignOnService endpoint = null; + for (SingleSignOnService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { + + // use POST binding as default if it exists + if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + endpoint = sss; + + } else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) + && endpoint == null ) + endpoint = sss; + + } + + if (endpoint == null) { + Logger.warn("Building AuthnRequest FAILED: > Requested IDP " + idpEntity.getEntityID() + + " does not support POST or Redirect Binding."); + throw new AuthnRequestBuildException("sp.pvp2.00", new Object[]{idpEntity.getEntityID()}); + + } else + authReq.setDestination(endpoint.getLocation()); + + + //set basic AuthnRequest information + SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + authReq.setID(gen.generateIdentifier()); + authReq.setIssueInstant(new DateTime()); + + //set isPassive flag + if (config.isPassivRequest() == null) + authReq.setIsPassive(false); + else + authReq.setIsPassive(config.isPassivRequest()); + + //set EntityID of the service provider + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + issuer.setFormat(NameIDType.ENTITY); + issuer.setValue(config.getSPEntityID()); + authReq.setIssuer(issuer); + + //set AssertionConsumerService ID + if (config.getAssertionConsumerServiceId() != null) + authReq.setAssertionConsumerServiceIndex(config.getAssertionConsumerServiceId()); + + //set NameIDPolicy + if (config.getNameIDPolicyFormat() != null) { + NameIDPolicy policy = SAML2Utils.createSAMLObject(NameIDPolicy.class); + policy.setAllowCreate(config.getNameIDPolicyAllowCreation()); + policy.setFormat(config.getNameIDPolicyFormat()); + authReq.setNameIDPolicy(policy); + } + + //set requested QAA level + if (config.getAuthnContextClassRef() != null) { + RequestedAuthnContext reqAuthContext = SAML2Utils.createSAMLObject(RequestedAuthnContext.class); + AuthnContextClassRef authnClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); + + authnClassRef.setAuthnContextClassRef(config.getAuthnContextClassRef()); + + if (config.getAuthnContextComparison() == null) + reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); + else + reqAuthContext.setComparison(config.getAuthnContextComparison()); + + reqAuthContext.getAuthnContextClassRefs().add(authnClassRef); + authReq.setRequestedAuthnContext(reqAuthContext); + } + + //TODO: implement requested attributes + //maybe: config.getRequestedAttributes(); + + //select message encoder + IEncoder binding = null; + if (endpoint.getBinding().equals( + SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + binding = new RedirectBinding(); + + } else if (endpoint.getBinding().equals( + SAMLConstants.SAML2_POST_BINDING_URI)) { + binding = new PostBinding(); + + } + + //encode message + binding.encodeRequest(null, httpResp, authReq, + endpoint.getLocation(), pendingReq.getRequestID(), config.getAuthnRequestSigningCredential()); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java new file mode 100644 index 000000000..3418ffb69 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java @@ -0,0 +1,460 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.builder; + +import java.io.IOException; +import java.io.StringWriter; +import java.security.PrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.joda.time.DateTime; +import org.opensaml.Configuration; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml2.metadata.LocalizedString; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml2.metadata.RoleDescriptor; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.ServiceName; +import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.SignatureException; +import org.opensaml.xml.signature.Signer; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPMetadataBuilderConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ + +@Service("PVPMetadataBuilder") +public class PVPMetadataBuilder { + + X509KeyInfoGeneratorFactory keyInfoFactory = null; + + /** + * + */ + public PVPMetadataBuilder() { + keyInfoFactory = new X509KeyInfoGeneratorFactory(); + keyInfoFactory.setEmitEntityIDAsKeyName(true); + keyInfoFactory.setEmitEntityCertificate(true); + + } + + + /** + * + * Build PVP 2.1 conform SAML2 metadata + * + * @param config + * PVPMetadataBuilder configuration + * + * @return PVP metadata as XML String + * @throws SecurityException + * @throws ConfigurationException + * @throws CredentialsNotAvailableException + * @throws TransformerFactoryConfigurationError + * @throws MarshallingException + * @throws TransformerException + * @throws ParserConfigurationException + * @throws IOException + * @throws SignatureException + */ + public String buildPVPMetadata(IPVPMetadataBuilderConfiguration config) throws CredentialsNotAvailableException, ConfigurationException, SecurityException, TransformerFactoryConfigurationError, MarshallingException, TransformerException, ParserConfigurationException, IOException, SignatureException { + DateTime date = new DateTime(); + EntityDescriptor entityDescriptor = SAML2Utils + .createSAMLObject(EntityDescriptor.class); + + //set entityID + entityDescriptor.setEntityID(config.getEntityID()); + + //set contact and organisation information + List<ContactPerson> contactPersons = config.getContactPersonInformation(); + if (contactPersons != null) + entityDescriptor.getContactPersons().addAll(contactPersons); + + Organization organisation = config.getOrgansiationInformation(); + if (organisation != null) + entityDescriptor.setOrganization(organisation); + + //set IDP metadata + if (config.buildIDPSSODescriptor()) { + RoleDescriptor idpSSODesc = generateIDPMetadata(config); + if (idpSSODesc != null) + entityDescriptor.getRoleDescriptors().add(idpSSODesc); + + } + + //set SP metadata for interfederation + if (config.buildSPSSODescriptor()) { + RoleDescriptor spSSODesc = generateSPMetadata(config); + if (spSSODesc != null) + entityDescriptor.getRoleDescriptors().add(spSSODesc); + + } + + //set metadata signature parameters + Credential metadataSignCred = config.getMetadataSigningCredentials(); + Signature signature = getIDPSignature(metadataSignCred); + SecurityHelper.prepareSignatureParams(signature, metadataSignCred, null, null); + + + //initialize XML document builder + DocumentBuilder builder; + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + + builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + + + //build entities descriptor + if (config.buildEntitiesDescriptorAsRootElement()) { + EntitiesDescriptor entitiesDescriptor = + SAML2Utils.createSAMLObject(EntitiesDescriptor.class); + entitiesDescriptor.setName(config.getEntityFriendlyName()); + entitiesDescriptor.setID(SAML2Utils.getSecureIdentifier()); + entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil())); + entitiesDescriptor.getEntityDescriptors().add(entityDescriptor); + + entitiesDescriptor.setSignature(signature); + + //marshall document + Marshaller out = Configuration.getMarshallerFactory() + .getMarshaller(entitiesDescriptor); + out.marshall(entitiesDescriptor, document); + + } else { + entityDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil())); + + entityDescriptor.setSignature(signature); + + //marshall document + Marshaller out = Configuration.getMarshallerFactory() + .getMarshaller(entityDescriptor); + out.marshall(entityDescriptor, document); + + } + + //sign metadata + Signer.signObject(signature); + + //transform metadata object to XML string + Transformer transformer = TransformerFactory.newInstance() + .newTransformer(); + + StringWriter sw = new StringWriter(); + StreamResult sr = new StreamResult(sw); + DOMSource source = new DOMSource(document); + transformer.transform(source, sr); + sw.close(); + + return sw.toString(); + } + + + private RoleDescriptor generateSPMetadata(IPVPMetadataBuilderConfiguration config) throws CredentialsNotAvailableException, SecurityException, ConfigurationException { + SPSSODescriptor spSSODescriptor = SAML2Utils.createSAMLObject(SPSSODescriptor.class); + spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); + spSSODescriptor.setAuthnRequestsSigned(true); + spSSODescriptor.setWantAssertionsSigned(false); + + KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); + + //Set AuthRequest Signing certificate + Credential authcredential = config.getRequestorResponseSigningCredentials(); + if (authcredential == null) { + Logger.warn("SP Metadata generation FAILED! --> Builder has NO request signing-credential. "); + return null; + + } else { + KeyDescriptor signKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + signKeyDescriptor.setUse(UsageType.SIGNING); + signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential)); + spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); + + } + + //Set assertion encryption credentials + Credential authEncCredential = config.getEncryptionCredentials(); + + if (authEncCredential != null) { + KeyDescriptor encryKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + encryKeyDescriptor.setUse(UsageType.ENCRYPTION); + encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential)); + spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor); + + } else { + Logger.warn("No Assertion Encryption-Key defined. This setting is not recommended!"); + + } + + //check nameID formates + if (config.getSPAllowedNameITTypes() == null || config.getSPAllowedNameITTypes().size() == 0) { + Logger.warn("SP Metadata generation FAILED! --> Builder has NO provideable SAML2 nameIDFormats. "); + return null; + + } else { + for (String format : config.getSPAllowedNameITTypes()) { + NameIDFormat nameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); + nameIDFormat.setFormat(format); + spSSODescriptor.getNameIDFormats().add(nameIDFormat); + + } + } + + + //add POST-Binding assertion consumer services + if (MiscUtil.isNotEmpty(config.getSPAssertionConsumerServicePostBindingURL())) { + AssertionConsumerService postassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); + postassertionConsumerService.setIndex(0); + postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + postassertionConsumerService.setLocation(config.getSPAssertionConsumerServicePostBindingURL()); + postassertionConsumerService.setIsDefault(true); + spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); + + } + + //add POST-Binding assertion consumer services + if (MiscUtil.isNotEmpty(config.getSPAssertionConsumerServiceRedirectBindingURL())) { + AssertionConsumerService redirectassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); + redirectassertionConsumerService.setIndex(1); + redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + redirectassertionConsumerService.setLocation(config.getSPAssertionConsumerServiceRedirectBindingURL()); + spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService); + + } + + //validate WebSSO endpoints + if (spSSODescriptor.getAssertionConsumerServices().size() == 0) { + Logger.warn("SP Metadata generation FAILED! --> NO SAML2 AssertionConsumerService endpoint found. "); + return null; + + } + + //add POST-Binding SLO descriptor + if (MiscUtil.isNotEmpty(config.getSPSLOPostBindingURL())) { + SingleLogoutService postSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + postSLOService.setLocation(config.getSPSLOPostBindingURL()); + postSLOService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(postSLOService); + + } + + //add POST-Binding SLO descriptor + if (MiscUtil.isNotEmpty(config.getSPSLORedirectBindingURL())) { + SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectSLOService.setLocation(config.getSPSLORedirectBindingURL()); + redirectSLOService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); + + } + + //add POST-Binding SLO descriptor + if (MiscUtil.isNotEmpty(config.getSPSLOSOAPBindingURL())) { + SingleLogoutService soapSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + soapSLOService.setLocation(config.getSPSLOSOAPBindingURL()); + soapSLOService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); + spSSODescriptor.getSingleLogoutServices().add(soapSLOService); + + } + + + //add required attributes + List<RequestedAttribute> reqSPAttr = config.getSPRequiredAttributes(); + AttributeConsumingService attributeService = SAML2Utils.createSAMLObject(AttributeConsumingService.class); + + attributeService.setIndex(0); + attributeService.setIsDefault(true); + ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class); + serviceName.setName(new LocalizedString("Default Service", "en")); + attributeService.getNames().add(serviceName); + + if (reqSPAttr != null && reqSPAttr.size() > 0) { + Logger.debug("Add " + reqSPAttr.size() + " attributes to SP metadata"); + attributeService.getRequestAttributes().addAll(reqSPAttr); + + } else { + Logger.debug("SP metadata contains NO requested attributes."); + + } + + spSSODescriptor.getAttributeConsumingServices().add(attributeService); + + return spSSODescriptor; + } + + private IDPSSODescriptor generateIDPMetadata(IPVPMetadataBuilderConfiguration config) throws ConfigurationException, CredentialsNotAvailableException, SecurityException { + //check response signing credential + Credential responseSignCred = config.getRequestorResponseSigningCredentials(); + if (responseSignCred == null) { + Logger.warn("IDP Metadata generation FAILED! --> Builder has NO Response signing credential. "); + return null; + + } + + //check nameID formates + if (config.getIDPPossibleNameITTypes() == null || config.getIDPPossibleNameITTypes().size() == 0) { + Logger.warn("IDP Metadata generation FAILED! --> Builder has NO provideable SAML2 nameIDFormats. "); + return null; + + } + + // build SAML2 IDP-SSO descriptor element + IDPSSODescriptor idpSSODescriptor = SAML2Utils + .createSAMLObject(IDPSSODescriptor.class); + + idpSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); + + //set ass default value, because PVP 2.x specification defines this feature as MUST + idpSSODescriptor.setWantAuthnRequestsSigned(true); + + // add WebSSO descriptor for POST-Binding + if (MiscUtil.isNotEmpty(config.getIDPWebSSOPostBindingURL())) { + SingleSignOnService postSingleSignOnService = SAML2Utils.createSAMLObject(SingleSignOnService.class); + postSingleSignOnService.setLocation(config.getIDPWebSSOPostBindingURL()); + postSingleSignOnService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + idpSSODescriptor.getSingleSignOnServices().add(postSingleSignOnService); + + } + + // add WebSSO descriptor for Redirect-Binding + if (MiscUtil.isNotEmpty(config.getIDPWebSSORedirectBindingURL())) { + SingleSignOnService postSingleSignOnService = SAML2Utils.createSAMLObject(SingleSignOnService.class); + postSingleSignOnService.setLocation(config.getIDPWebSSORedirectBindingURL()); + postSingleSignOnService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + idpSSODescriptor.getSingleSignOnServices().add(postSingleSignOnService); + + } + + //add Single LogOut POST-Binding endpoing + if (MiscUtil.isNotEmpty(config.getIDPSLOPostBindingURL())) { + SingleLogoutService postSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + postSLOService.setLocation(config.getIDPSLOPostBindingURL()); + postSLOService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + idpSSODescriptor.getSingleLogoutServices().add(postSLOService); + + } + + //add Single LogOut Redirect-Binding endpoing + if (MiscUtil.isNotEmpty(config.getIDPSLORedirectBindingURL())) { + SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); + redirectSLOService.setLocation(config.getIDPSLORedirectBindingURL()); + redirectSLOService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService); + + } + + //validate WebSSO endpoints + if (idpSSODescriptor.getSingleSignOnServices().size() == 0) { + Logger.warn("IDP Metadata generation FAILED! --> NO SAML2 SingleSignOnService endpoint found. "); + return null; + + } + + //set assertion signing key + KeyDescriptor signKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + signKeyDescriptor.setUse(UsageType.SIGNING); + KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); + signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(config.getRequestorResponseSigningCredentials())); + idpSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); + + //set IDP attribute set + idpSSODescriptor.getAttributes().addAll(config.getIDPPossibleAttributes()); + + //set providable nameID formats + for (String format : config.getIDPPossibleNameITTypes()) { + NameIDFormat nameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); + nameIDFormat.setFormat(format); + idpSSODescriptor.getNameIDFormats().add(nameIDFormat); + + } + + return idpSSODescriptor; + + } + + private Signature getIDPSignature(Credential credentials) { + PrivateKey privatekey = credentials.getPrivateKey(); + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + + if (privatekey instanceof RSAPrivateKey) { + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); + + } else if (privatekey instanceof iaik.security.ecc.ecdsa.ECPrivateKey) { + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); + + } else { + Logger.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential."); + + + } + + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(credentials); + return signer; + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java index 50f42d928..a7fc8295a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java @@ -23,12 +23,16 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.builder; import java.security.NoSuchAlgorithmException; +import java.util.LinkedHashMap; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.joda.time.DateTime; +import org.opensaml.Configuration; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.impl.SecureRandomIdentifierGenerator; @@ -43,33 +47,41 @@ import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.StatusMessage; import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.SSODescriptor; import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder; import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.io.Marshaller; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.Signer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +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.config.ConfigurationException; +import at.gv.egovernment.moa.id.data.ISLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.logging.Logger; @@ -78,9 +90,12 @@ import at.gv.egovernment.moa.logging.Logger; * @author tlenz * */ +@Service("PVP_SingleLogOutBuilder") public class SingleLogOutBuilder { - public static void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { + @Autowired private IDPCredentialProvider credentialProvider; + + public void checkStatusCode(ISLOInformationContainer sloContainer, LogoutResponse logOutResp) { Status status = logOutResp.getStatus(); if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { String message = " Message: "; @@ -106,12 +121,12 @@ public class SingleLogOutBuilder { * @param relayState * @return */ - public static String getFrontChannelSLOMessageURL(String serviceURL, String bindingType, + public String getFrontChannelSLOMessageURL(String serviceURL, String bindingType, RequestAbstractType sloReq, HttpServletRequest httpReq, HttpServletResponse httpResp, String relayState) throws MOAIDException { try { - X509Credential credentials = CredentialProvider + X509Credential credentials = credentialProvider .getIDPAssertionSigningCredential(); Logger.debug("create SAML RedirectBinding response"); @@ -138,12 +153,12 @@ public class SingleLogOutBuilder { } } - public static String getFrontChannelSLOMessageURL(SingleLogoutService service, + public String getFrontChannelSLOMessageURL(SingleLogoutService service, StatusResponseType sloResp, HttpServletRequest httpReq, HttpServletResponse httpResp, String relayState) throws MOAIDException { try { - X509Credential credentials = CredentialProvider + X509Credential credentials = credentialProvider .getIDPAssertionSigningCredential(); Logger.debug("create SAML RedirectBinding response"); @@ -166,7 +181,7 @@ public class SingleLogOutBuilder { } } - public static void sendFrontChannelSLOMessage(SingleLogoutService consumerService, + public void sendFrontChannelSLOMessage(SingleLogoutService consumerService, LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp, String relayState) throws MOAIDException { IEncoder binding = null; @@ -186,7 +201,8 @@ public class SingleLogOutBuilder { try { binding.encodeRespone(req, resp, sloResp, - consumerService.getLocation(), relayState); + consumerService.getLocation(), relayState, + credentialProvider.getIDPAssertionSigningCredential()); } catch (MessageEncodingException e) { Logger.error("Message Encoding exception", e); @@ -200,7 +216,7 @@ public class SingleLogOutBuilder { } - public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException, MOAIDException { + public LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException, MOAIDException { LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); SecureRandomIdentifierGenerator gen; @@ -215,8 +231,8 @@ public class SingleLogOutBuilder { } DateTime now = new DateTime(); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + issuer.setValue(sloInfo.getAuthURL()); issuer.setFormat(NameID.ENTITY); sloReq.setIssuer(issuer); sloReq.setIssueInstant(now); @@ -228,11 +244,39 @@ public class SingleLogOutBuilder { nameID.setFormat(sloInfo.getUserNameIDFormat()); nameID.setValue(sloInfo.getUserNameIdentifier()); sloReq.setNameID(nameID ); - + + //sign message + try { + X509Credential idpSigningCredential = credentialProvider.getIDPAssertionSigningCredential(); + + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(idpSigningCredential); + sloReq.setSignature(signer); + + DocumentBuilder builder; + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + + builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory() + .getMarshaller(sloReq); + out.marshall(sloReq, document); + + Signer.signObject(signer); + + } catch (Exception e) { + Logger.error("Single LogOut request signing FAILED!", e); + throw new MOAIDException("pvp2.19", null); + + } + return sloReq; } - public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest, String firstLevelStatusCode) throws ConfigurationException, MOAIDException { + public LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest, String firstLevelStatusCode) throws ConfigurationException, MOAIDException { LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); Status status = SAML2Utils.createSAMLObject(Status.class); @@ -249,7 +293,7 @@ public class SingleLogOutBuilder { return sloResp; } - public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws MOAIDException { + public LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws MOAIDException { LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); Status status; @@ -274,10 +318,10 @@ public class SingleLogOutBuilder { } - private static LogoutResponse buildBasicResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { + private LogoutResponse buildBasicResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + issuer.setValue(spRequest.getAuthURLWithOutSlash()); issuer.setFormat(NameID.ENTITY); sloResp.setIssuer(issuer); sloResp.setIssueInstant(new DateTime()); @@ -305,7 +349,7 @@ public class SingleLogOutBuilder { } - public static SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException { + public SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException { try { EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID); SSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); @@ -346,7 +390,7 @@ public class SingleLogOutBuilder { } - public static SingleLogoutService getResponseSLODescriptor(PVPTargetConfiguration spRequest) throws NoMetadataInformationException, NOSLOServiceDescriptorException { + public SingleLogoutService getResponseSLODescriptor(PVPTargetConfiguration spRequest) throws NoMetadataInformationException, NOSLOServiceDescriptorException { MOARequest moaReq = (MOARequest) spRequest.getRequest(); EntityDescriptor metadata = moaReq.getEntityMetadata(); SSODescriptor ssodesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); @@ -382,4 +426,91 @@ public class SingleLogOutBuilder { return sloService; } + public void parseActiveOAs(SLOInformationContainer container, + List<OASessionStore> dbOAs, String removeOAID) { + if (container.getActiveBackChannelOAs() == null) + container.setActiveBackChannelOAs(new LinkedHashMap<String, SLOInformationImpl>()); + if (container.getActiveFrontChannalOAs() == null) + container.setActiveFrontChannalOAs(new LinkedHashMap<String, SLOInformationImpl>()); + + + if (dbOAs != null) { + for (OASessionStore oa : dbOAs) { + if (!oa.getOaurlprefix().equals(removeOAID)) { + + //Actually only PVP 2.1 support Single LogOut + if (PVP2XProtocol.PATH.equals(oa.getProtocolType())) { + SingleLogoutService sloDesc; + try { + sloDesc = getRequestSLODescriptor(oa.getOaurlprefix()); + + if (sloDesc.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) + container.getActiveBackChannelOAs().put(oa.getOaurlprefix(), + new SLOInformationImpl( + oa.getAuthURL(), + oa.getAssertionSessionID(), + oa.getUserNameID(), + oa.getUserNameIDFormat(), + oa.getProtocolType(), + sloDesc)); + + else + container.getActiveFrontChannalOAs().put(oa.getOaurlprefix(), + new SLOInformationImpl( + oa.getAuthURL(), + oa.getAssertionSessionID(), + oa.getUserNameID(), + oa.getUserNameIDFormat(), + oa.getProtocolType(), + sloDesc)); + + } catch (NOSLOServiceDescriptorException e) { + container.putFailedOA(oa.getOaurlprefix()); + + } + + } else + container.putFailedOA(oa.getOaurlprefix()); + } + } + } + } + + /** + * @param dbIDPs + * @param value + */ + public void parseActiveIDPs(SLOInformationContainer container, + List<InterfederationSessionStore> dbIDPs, String removeIDP) { + if (container.getActiveBackChannelOAs() == null) + container.setActiveBackChannelOAs(new LinkedHashMap<String, SLOInformationImpl>()); + if (container.getActiveFrontChannalOAs() == null) + container.setActiveFrontChannalOAs(new LinkedHashMap<String, SLOInformationImpl>()); + + if (dbIDPs != null) { + for (InterfederationSessionStore el : dbIDPs) { + if (!el.getIdpurlprefix().equals(removeIDP)) { + + SingleLogoutService sloDesc; + try { + sloDesc = getRequestSLODescriptor(el.getIdpurlprefix()); + + container.getActiveFrontChannalOAs().put(el.getIdpurlprefix(), + new SLOInformationImpl( + el.getAuthURL(), + el.getSessionIndex(), + el.getUserNameID(), + NameID.TRANSIENT, + PVP2XProtocol.PATH, + sloDesc)); + + } catch (NOSLOServiceDescriptorException e) { + container.putFailedOA(el.getIdpurlprefix()); + + } + } + } + } + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java index d80ddba25..94e30238a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java @@ -55,7 +55,6 @@ import org.opensaml.saml2.metadata.RequestedAttribute; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.w3c.dom.Element; - import at.gv.e_government.reference.namespace.mandates._20040701_.Mandate; import at.gv.e_government.reference.namespace.persondata._20020228_.CorporateBodyType; import at.gv.e_government.reference.namespace.persondata._20020228_.IdentificationType; @@ -64,21 +63,18 @@ import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; -import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationImpl; +import at.gv.egovernment.moa.id.moduls.IRequest; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.UnavailableAttributeException; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.MandateAttributesNotHandleAbleException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMandateDataAvailableException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.PVP2Exception; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.QAANotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.UnprovideableAttributeException; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.CheckMandateAttributes; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.MandateBuilder; import at.gv.egovernment.moa.id.util.QAALevelVerifier; @@ -90,7 +86,7 @@ import at.gv.egovernment.moa.util.MiscUtil; public class PVP2AssertionBuilder implements PVPConstants { - public static Assertion buildAssertion(AttributeQuery attrQuery, + public static Assertion buildAssertion(IRequest pendingReq, AttributeQuery attrQuery, List<String> reqAttributes, IAuthData authData, DateTime date, String sessionIndex) throws ConfigurationException { @@ -136,12 +132,12 @@ public class PVP2AssertionBuilder implements PVPConstants { SubjectConfirmationData subjectConfirmationData = null; - return buildGenericAssertion(attrQuery.getIssuer().getValue(), date, + return buildGenericAssertion(pendingReq, attrQuery.getIssuer().getValue(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, new DateTime(authData.getSsoSessionValidTo().getTime())); } - public static Assertion buildAssertion(AuthnRequest authnRequest, + public static Assertion buildAssertion(PVPTargetConfiguration pendingReq, AuthnRequest authnRequest, IAuthData authData, EntityDescriptor peerEntity, DateTime date, AssertionConsumerService assertionConsumerService, SLOInformationImpl sloInformation) throws MOAIDException { @@ -153,9 +149,7 @@ public class PVP2AssertionBuilder implements PVPConstants { AuthnContextClassRef authnContextClassRef = SAML2Utils .createSAMLObject(AuthnContextClassRef.class); - OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance() - .getOnlineApplicationParameter( - peerEntity.getEntityID()); + IOAAuthParameters oaParam = pendingReq.getOnlineApplicationConfiguration(); if (reqAuthnContext == null) { authnContextClassRef.setAuthnContextClassRef(authData.getQAALevel()); @@ -416,10 +410,25 @@ public class PVP2AssertionBuilder implements PVPConstants { sloInformation.setNameIDFormat(subjectNameID.getFormat()); sloInformation.setSessionIndex(sessionIndex); - return buildGenericAssertion(peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); + return buildGenericAssertion(pendingReq, peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); } - public static Assertion buildGenericAssertion(String entityID, DateTime date, + /** + * + * @param pendingReq IDP PublicURL PreFix + * @param entityID Service Provider EntityID + * @param date + * @param authnContextClassRef + * @param attrList + * @param subjectNameID + * @param subjectConfirmationData + * @param sessionIndex + * @param isValidTo + * @return + * @throws ConfigurationException + */ + + public static Assertion buildGenericAssertion(IRequest pendingReq, String entityID, DateTime date, AuthnContextClassRef authnContextClassRef, List<Attribute> attrList, NameID subjectNameID, SubjectConfirmationData subjectConfirmationData, String sessionIndex, DateTime isValidTo) throws ConfigurationException { @@ -471,7 +480,10 @@ public class PVP2AssertionBuilder implements PVPConstants { Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + String authURL = pendingReq.getAuthURL(); + if (authURL.endsWith("/")) + authURL = authURL.substring(0, authURL.length()-1); + issuer.setValue(authURL); issuer.setFormat(NameID.ENTITY); assertion.setIssuer(issuer); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IDPPVPMetadataConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IDPPVPMetadataConfiguration.java new file mode 100644 index 000000000..e0994ff19 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IDPPVPMetadataConfiguration.java @@ -0,0 +1,288 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.config; + +import java.util.Arrays; +import java.util.List; + +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.xml.security.credential.Credential; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.IDPCredentialProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +public class IDPPVPMetadataConfiguration implements IPVPMetadataBuilderConfiguration { + + private static final int VALIDUNTIL_IN_HOURS = 24; + + private String authURL; + private IDPCredentialProvider credentialProvider; + + public IDPPVPMetadataConfiguration(String authURL, IDPCredentialProvider credentialProvider) { + this.authURL = authURL; + this.credentialProvider = credentialProvider; + + } + + public String getDefaultActionName() { + return (PVP2XProtocol.METADATA); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getMetadataValidUntil() + */ + @Override + public int getMetadataValidUntil() { + return VALIDUNTIL_IN_HOURS; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#buildEntitiesDescriptorAsRootElement() + */ + @Override + public boolean buildEntitiesDescriptorAsRootElement() { + return true; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#buildIDPSSODescriptor() + */ + @Override + public boolean buildIDPSSODescriptor() { + return true; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#buildSPSSODescriptor() + */ + @Override + public boolean buildSPSSODescriptor() { + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getEntityID() + */ + @Override + public String getEntityID() { + return authURL; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getEntityFriendlyName() + */ + @Override + public String getEntityFriendlyName() { + try { + return PVPConfiguration.getInstance().getIDPIssuerName(); + + } catch (ConfigurationException e) { + Logger.error("Can not load Metadata entry: EntityID friendlyName.", e); + return null; + + } + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getContactPersonInformation() + */ + @Override + public List<ContactPerson> getContactPersonInformation() { + try { + return PVPConfiguration.getInstance().getIDPContacts(); + + } catch (ConfigurationException e) { + Logger.warn("Can not load Metadata entry: Contect Person", e); + return null; + + } + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getOrgansiationInformation() + */ + @Override + public Organization getOrgansiationInformation() { + try { + return PVPConfiguration.getInstance().getIDPOrganisation(); + + } catch (ConfigurationException e) { + Logger.warn("Can not load Metadata entry: Organisation", e); + return null; + + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getMetadataSigningCredentials() + */ + @Override + public Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIDPMetaDataSigningCredential(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getRequestorResponseSigningCredentials() + */ + @Override + public Credential getRequestorResponseSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIDPAssertionSigningCredential(); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getEncryptionCredentials() + */ + @Override + public Credential getEncryptionCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIDPAssertionEncryptionCredential(); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPWebSSOPostBindingURL() + */ + @Override + public String getIDPWebSSOPostBindingURL() { + return authURL + PVPConfiguration.PVP2_IDP_POST; + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPWebSSORedirectBindingURL() + */ + @Override + public String getIDPWebSSORedirectBindingURL() { + return authURL + PVPConfiguration.PVP2_IDP_REDIRECT; + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPSLOPostBindingURL() + */ + @Override + public String getIDPSLOPostBindingURL() { + return authURL + PVPConfiguration.PVP2_IDP_POST; + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPSLORedirectBindingURL() + */ + @Override + public String getIDPSLORedirectBindingURL() { + return authURL + PVPConfiguration.PVP2_IDP_REDIRECT; + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPAssertionConsumerServicePostBindingURL() + */ + @Override + public String getSPAssertionConsumerServicePostBindingURL() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPAssertionConsumerServiceRedirectBindingURL() + */ + @Override + public String getSPAssertionConsumerServiceRedirectBindingURL() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPSLOPostBindingURL() + */ + @Override + public String getSPSLOPostBindingURL() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPSLORedirectBindingURL() + */ + @Override + public String getSPSLORedirectBindingURL() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPSLOSOAPBindingURL() + */ + @Override + public String getSPSLOSOAPBindingURL() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPPossibleAttributes() + */ + @Override + public List<Attribute> getIDPPossibleAttributes() { + return PVPAttributeBuilder.buildSupportedEmptyAttributes(); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getIDPPossibleNameITTypes() + */ + @Override + public List<String> getIDPPossibleNameITTypes() { + return Arrays.asList(NameIDType.PERSISTENT, + NameIDType.TRANSIENT, + NameIDType.UNSPECIFIED); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPRequiredAttributes() + */ + @Override + public List<RequestedAttribute> getSPRequiredAttributes() { + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder#getSPAllowedNameITTypes() + */ + @Override + public List<String> getSPAllowedNameITTypes() { + return null; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPAuthnRequestBuilderConfiguruation.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPAuthnRequestBuilderConfiguruation.java new file mode 100644 index 000000000..d51231044 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPAuthnRequestBuilderConfiguruation.java @@ -0,0 +1,114 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.config; + +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.xml.security.credential.Credential; + +/** + * @author tlenz + * + */ +public interface IPVPAuthnRequestBuilderConfiguruation { + + /** + * If true, the SAML2 isPassive flag is set in the AuthnRequest + * + * @return + */ + public Boolean isPassivRequest(); + + /** + * Define the ID of the AssertionConsumerService, + * which defines the required attributes in service-provider metadata. + * + * @return + */ + public Integer getAssertionConsumerServiceId(); + + /** + * Define the SAML2 EntityID of the service provider. + * + * @return + */ + public String getSPEntityID(); + + /** + * Define the SAML2 NameIDPolicy + * + * @return Service-Provider EntityID, but never null + */ + public String getNameIDPolicyFormat(); + + /** + * Define the AuthnContextClassRefernece of this request + * + * Example: + * http://www.ref.gv.at/ns/names/agiz/pvp/secclass/0-3 + * http://www.stork.gov.eu/1.0/citizenQAALevel/4 + * + * + * @return + */ + public String getAuthnContextClassRef(); + + /** + * Define the AuthnContextComparison model, which should be used + * + * @return + */ + public AuthnContextComparisonTypeEnumeration getAuthnContextComparison(); + + + /** + * Define the credential, which should be used to sign the AuthnRequest + * + * @return + */ + public Credential getAuthnRequestSigningCredential(); + + + /** + * Define the SAML2 EntityDescriptor of the IDP, which should receive the AuthnRequest + * + * @return Credential, but never null. + */ + public EntityDescriptor getIDPEntityDescriptor(); + + /** + * Set the SAML2 NameIDPolicy allow-creation flag + * + * @return EntityDescriptor, but never null. + */ + public boolean getNameIDPolicyAllowCreation(); + + + /** + * Set the requested SubjectNameID + * + * @return SubjectNameID, or null if no SubjectNameID should be used + */ + public String getSubjectNameID(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPMetadataBuilderConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPMetadataBuilderConfiguration.java new file mode 100644 index 000000000..52096fd19 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/IPVPMetadataBuilderConfiguration.java @@ -0,0 +1,217 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.config; + +import java.util.List; + +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.xml.security.credential.Credential; + +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; + +/** + * @author tlenz + * + */ +public interface IPVPMetadataBuilderConfiguration { + + + /** + * Set metadata valid area + * + * @return valid until in hours [h] + */ + public int getMetadataValidUntil(); + + /** + * Build a SAML2 Entities element as metadata root element + * + * @return true, if the metadata should start with entities element + */ + public boolean buildEntitiesDescriptorAsRootElement(); + + /** + * + * + * @return true, if an IDP SSO-descriptor element should be generated + */ + public boolean buildIDPSSODescriptor(); + + /** + * + * + * @return true, if an SP SSO-descriptor element should be generated + */ + public boolean buildSPSSODescriptor(); + + /** + * Set the PVP entityID for this SAML2 metadata. + * The entityID must be an URL and must be start with the public-URL prefix of the server + * + * @return PVP entityID postfix as String + */ + public String getEntityID(); + + /** + * Set a friendlyName for this PVP entity + * + * @return + */ + public String getEntityFriendlyName(); + + /** + * Set the contact information for this metadata entity + * + * @return + */ + public List<ContactPerson> getContactPersonInformation(); + + /** + * Set organisation information for this metadata entity + * + * @return + */ + public Organization getOrgansiationInformation(); + + + /** + * Set the credential for metadata signing + * + * @return + * @throws CredentialsNotAvailableException + */ + public Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException; + + /** + * Set the credential for request/response signing + * IDP metadata: this credential is used for SAML2 response signing + * SP metadata: this credential is used for SAML2 response signing + * + * @return + * @throws CredentialsNotAvailableException + */ + public Credential getRequestorResponseSigningCredentials() throws CredentialsNotAvailableException; + + /** + * Set the credential for response encryption + * + * @return + * @throws CredentialsNotAvailableException + */ + public Credential getEncryptionCredentials() throws CredentialsNotAvailableException; + + /** + * Set the IDP Post-Binding URL for WebSSO + * + * @return + */ + public String getIDPWebSSOPostBindingURL(); + + /** + * Set the IDP Redirect-Binding URL for WebSSO + * + * @return + */ + public String getIDPWebSSORedirectBindingURL(); + + /** + * Set the IDP Post-Binding URL for Single LogOut + * + * @return + */ + public String getIDPSLOPostBindingURL(); + + /** + * Set the IDP Redirect-Binding URL for Single LogOut + * + * @return + */ + public String getIDPSLORedirectBindingURL(); + + /** + * Set the SP Post-Binding URL for for the Assertion-Consumer Service + * + * @return + */ + public String getSPAssertionConsumerServicePostBindingURL(); + + /** + * Set the SP Redirect-Binding URL for the Assertion-Consumer Service + * + * @return + */ + public String getSPAssertionConsumerServiceRedirectBindingURL(); + + /** + * Set the SP Post-Binding URL for Single LogOut + * + * @return + */ + public String getSPSLOPostBindingURL(); + + /** + * Set the SP Redirect-Binding URL for Single LogOut + * + * @return + */ + public String getSPSLORedirectBindingURL(); + + /** + * Set the SP SOAP-Binding URL for Single LogOut + * + * @return + */ + public String getSPSLOSOAPBindingURL(); + + + /** + * Set all SAML2 attributes which could be provided by this IDP + * + * @return + */ + public List<Attribute> getIDPPossibleAttributes(); + + /** + * Set all nameID types which could be provided by this IDP + * + * @return a List of SAML2 nameID types + */ + public List<String> getIDPPossibleNameITTypes(); + + /** + * Set all SAML2 attributes which are required by the SP + * + * @return + */ + public List<RequestedAttribute> getSPRequiredAttributes(); + + /** + * Set all nameID types which allowed from the SP + * + * @return a List of SAML2 nameID types + */ + public List<String> getSPAllowedNameITTypes(); +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java index dc3b787e4..bbf395a6f 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java @@ -22,8 +22,6 @@ *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x.config; -import iaik.x509.X509Certificate; - import java.io.IOException; import java.net.URL; import java.security.cert.CertificateException; @@ -51,12 +49,11 @@ import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; -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.logging.Logger; import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; +import iaik.x509.X509Certificate; public class PVPConfiguration { @@ -79,18 +76,6 @@ public class PVPConfiguration { public static final String PVP_CONFIG_FILE = "pvp2config.properties"; - public static final String IDP_JAVAKEYSTORE = "idp.ks.file"; - public static final String IDP_KS_PASS = "idp.ks.kspassword"; - - public static final String IDP_KEYALIASMETADATA = "idp.ks.metadata.alias"; - public static final String IDP_KEY_PASSMETADATA = "idp.ks.metadata.keypassword"; - - public static final String IDP_KEYALIASASSERTION = "idp.ks.assertion.sign.alias"; - public static final String IDP_KEY_PASSASSERTION = "idp.ks.assertion.sign.keypassword"; - - public static final String IDP_KEYALIASENCRYTPION = "sp.ks.assertion.encryption.alias"; - public static final String IDP_KEY_PASSENCRYTPION = "sp.ks.assertion.encryption.keypassword"; - public static final String IDP_ISSUER_NAME = "servicename"; public static final String IDP_ORG_NAME = "name.short"; @@ -121,75 +106,46 @@ public class PVPConfiguration { } } - public String getIDPPublicPath() throws ConfigurationException { - String publicPath = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix(); - if(publicPath != null) { - if(publicPath.endsWith("/")) { - int length = publicPath.length(); - publicPath = publicPath.substring(0, length-1); - } + public List<String> getIDPPublicPath() throws ConfigurationException { + List<String> publicPath = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix(); + List<String> returnvalue = new ArrayList<String>(); + for (String el : publicPath) { + if(el.endsWith("/")) { + int length = el.length(); + returnvalue.add(el.substring(0, length-1)); + + } else + returnvalue.add(el); } - return publicPath; + return returnvalue; } - public String getSPSSOPostService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_SP_POST; + public String getSPSSOPostService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_SP_POST; } - public String getSPSSORedirectService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_SP_REDIRECT; + public String getSPSSORedirectService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_SP_REDIRECT; } - public String getIDPSSOPostService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_IDP_POST; + public String getIDPSSOPostService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_IDP_POST; } - public String getIDPSSORedirectService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_IDP_REDIRECT; + public String getIDPSSORedirectService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_IDP_REDIRECT; } - public String getIDPSSOSOAPService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_IDP_SOAP; + public String getIDPSSOSOAPService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_IDP_SOAP; } - public String getIDPAttributeQueryService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_IDP_ATTRIBUTEQUERY; + public String getIDPAttributeQueryService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_IDP_ATTRIBUTEQUERY; } - public String getIDPSSOMetadataService() throws ConfigurationException { - return getIDPPublicPath() + PVP2_METADATA; - } - - public String getIDPKeyStoreFilename() { - return FileUtils.makeAbsoluteURL(props.getProperty(IDP_JAVAKEYSTORE), rootDir); - } - - public String getIDPKeyStorePassword() { - return props.getProperty(IDP_KS_PASS).trim(); - } - - public String getIDPKeyAliasMetadata() { - return props.getProperty(IDP_KEYALIASMETADATA).trim(); - } - - public String getIDPKeyPasswordMetadata() { - return props.getProperty(IDP_KEY_PASSMETADATA).trim(); - } - - public String getIDPKeyAliasAssertionSign() { - return props.getProperty(IDP_KEYALIASASSERTION).trim(); - } - - public String getIDPKeyPasswordAssertionSign() { - return props.getProperty(IDP_KEY_PASSASSERTION).trim(); - } - - public String getIDPKeyAliasAssertionEncryption() { - return props.getProperty(IDP_KEYALIASASSERTION).trim(); - } - - public String getIDPKeyPasswordAssertionEncryption() { - return props.getProperty(IDP_KEY_PASSASSERTION).trim(); + public String getIDPSSOMetadataService(String publicURLPrefix) throws ConfigurationException { + return publicURLPrefix + PVP2_METADATA; } public String getIDPIssuerName() throws ConfigurationException { 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/exceptions/AuthnRequestBuildException.java index 293dccf6c..eebaf6c9e 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/exceptions/AuthnRequestBuildException.java @@ -1,4 +1,4 @@ -/******************************************************************************* +/* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. @@ -19,22 +19,29 @@ * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler; + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.exceptions; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +/** + * @author tlenz + * + */ +public class AuthnRequestBuildException extends PVP2Exception { -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.data.IAuthData; -import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; + /** + * + */ + private static final long serialVersionUID = -1375451065455859354L; -public interface IRequestHandler { - public boolean handleObject(InboundMessage obj); + /** + * @param messageId + * @param parameters + */ + public AuthnRequestBuildException(String messageId, Object[] parameters) { + super(messageId, parameters); + } - public SLOInformationInterface process(PVPTargetConfiguration pvpRequest, HttpServletRequest req, - HttpServletResponse resp, IAuthData authData) throws MOAIDException; + public AuthnRequestBuildException(String messageId, Object[] parameters, Throwable e) { + super(messageId, parameters, e); + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/AuthnResponseValidationException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/AuthnResponseValidationException.java new file mode 100644 index 000000000..957f9af1d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/AuthnResponseValidationException.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.exceptions; + +/** + * @author tlenz + * + */ +public class AuthnResponseValidationException extends PVP2Exception { + + /** + * + */ + private static final long serialVersionUID = 8023812861029406575L; + + /** + * @param messageId + * @param parameters + */ + public AuthnResponseValidationException(String messageId, Object[] parameters) { + super(messageId, parameters); + } + + public AuthnResponseValidationException(String messageId, Object[] parameters, Throwable e) { + super(messageId, parameters, e); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/InvalidAssertionConsumerServiceException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/InvalidAssertionConsumerServiceException.java index 94a4e8226..392569366 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/InvalidAssertionConsumerServiceException.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/exceptions/InvalidAssertionConsumerServiceException.java @@ -34,6 +34,15 @@ public class InvalidAssertionConsumerServiceException extends PVP2Exception { /** * */ + public InvalidAssertionConsumerServiceException(String wrongURL) { + super("pvp2.23", new Object[]{wrongURL}); + this.statusCodeValue = StatusCode.REQUESTER_URI; + + } + + /** + * + */ private static final long serialVersionUID = 7861790149343943091L; } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/ArtifactResolution.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/ArtifactResolution.java deleted file mode 100644 index 7f6054f2d..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/ArtifactResolution.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.joda.time.DateTime; -import org.opensaml.common.binding.artifact.SAMLArtifactMap.SAMLArtifactMapEntry; -import org.opensaml.saml2.core.ArtifactResolve; -import org.opensaml.saml2.core.ArtifactResponse; - -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.data.IAuthData; -import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPAssertionStorage; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; -import at.gv.egovernment.moa.id.protocols.pvp2x.binding.SoapBinding; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.RequestDeniedException; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import at.gv.egovernment.moa.logging.Logger; - -public class ArtifactResolution implements IRequestHandler { - - public boolean handleObject(InboundMessage obj) { - return (obj instanceof MOARequest && - ((MOARequest)obj).getSamlRequest() instanceof ArtifactResolve); - } - - public SLOInformationInterface process(PVPTargetConfiguration obj, HttpServletRequest req, - HttpServletResponse resp, IAuthData authData) throws MOAIDException { - if (!handleObject(obj.getRequest())) { - throw new MOAIDException("pvp2.13", null); - } - - ArtifactResolve artifactResolve = (ArtifactResolve) ((MOARequest)obj.getRequest()).getSamlRequest(); - String artifactID = artifactResolve.getArtifact().getArtifact(); - - PVPAssertionStorage pvpAssertion = PVPAssertionStorage.getInstance(); - - if (!pvpAssertion.contains(artifactID)) { - throw new RequestDeniedException(); - } else { - try { - SAMLArtifactMapEntry assertion = pvpAssertion.get(artifactID); - ArtifactResponse response = SAML2Utils - .createSAMLObject(ArtifactResponse.class); - response.setMessage(assertion.getSamlMessage()); - response.setIssueInstant(new DateTime()); - SoapBinding encoder = new SoapBinding(); - encoder.encodeRespone(req, resp, response, null, null); - } catch (Exception e) { - Logger.error("Failed to resolve artifact", e); - } - } - - return null; - } - -} 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 deleted file mode 100644 index a31258784..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/AuthnRequestHandler.java +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.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.Assertion; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.ws.message.encoder.MessageEncodingException; -import org.opensaml.xml.security.SecurityException; - -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.data.IAuthData; -import at.gv.egovernment.moa.id.data.SLOInformationImpl; -import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.binding.ArtifactBinding; -import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.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.builder.AuthResponseBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.assertion.PVP2AssertionBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import at.gv.egovernment.moa.logging.Logger; - -public class AuthnRequestHandler implements IRequestHandler, PVPConstants { - - public boolean handleObject(InboundMessage obj) { - - return (obj instanceof MOARequest && - ((MOARequest)obj).getSamlRequest() instanceof AuthnRequest); - } - - public SLOInformationInterface process(PVPTargetConfiguration obj, HttpServletRequest req, - HttpServletResponse resp, IAuthData authData) throws MOAIDException { - if (!handleObject(obj.getRequest())) { - throw new MOAIDException("pvp2.13", null); - } - - //get basic information - MOARequest moaRequest = (MOARequest) obj.getRequest(); - AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest(); - EntityDescriptor peerEntity = moaRequest.getEntityMetadata(); - - AssertionConsumerService consumerService = - SAML2Utils.createSAMLObject(AssertionConsumerService.class); - consumerService.setBinding(obj.getBinding()); - consumerService.setLocation(obj.getConsumerURL()); - - DateTime date = new DateTime(); - - SLOInformationImpl sloInformation = new SLOInformationImpl(); - - //build Assertion - Assertion assertion = PVP2AssertionBuilder.buildAssertion(authnRequest, authData, - peerEntity, date, consumerService, sloInformation); - - Response authResponse = AuthResponseBuilder.buildResponse(authnRequest, date, assertion); - - IEncoder binding = null; - - if (consumerService.getBinding().equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = new RedirectBinding(); - - } else if (consumerService.getBinding().equals( - SAMLConstants.SAML2_ARTIFACT_BINDING_URI)) { - // TODO: not supported YET!! - binding = new ArtifactBinding(); - - } 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, authResponse, - consumerService.getLocation(), moaRequest.getRelayState()); - - return sloInformation; - - } catch (MessageEncodingException e) { - Logger.error("Message Encoding exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } catch (SecurityException e) { - Logger.error("Security exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } - } -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java deleted file mode 100644 index b58b09f12..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/requestHandler/RequestManager.java +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.protocols.pvp2x.requestHandler; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.data.AuthenticationData; -import at.gv.egovernment.moa.id.data.IAuthData; -import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; -import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SAMLRequestNotSupported; - -public class RequestManager { - - private static RequestManager instance = null; - - private List<IRequestHandler> handler; - - public static synchronized RequestManager getInstance() { - if(instance == null) { - instance = new RequestManager(); - } - return instance; - } - - private RequestManager() { - handler = new ArrayList<IRequestHandler>(); - handler.add(new AuthnRequestHandler()); - handler.add(new ArtifactResolution()); - } - - public SLOInformationInterface handle(PVPTargetConfiguration pvpRequest, HttpServletRequest req, HttpServletResponse resp, IAuthData authData) - throws SAMLRequestNotSupported, MOAIDException { - Iterator<IRequestHandler> it = handler.iterator(); - while(it.hasNext()) { - IRequestHandler handler = it.next(); - if(handler.handleObject(pvpRequest.getRequest())) { - return handler.process(pvpRequest, req, resp, authData); - } - } - - // not handled - throw new SAMLRequestNotSupported(); - } -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java new file mode 100644 index 000000000..e7df23d61 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + *******************************************************************************/ +package at.gv.egovernment.moa.id.protocols.pvp2x.signer; + +import java.security.KeyStore; + +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.x509.X509Credential; + +import at.gv.egovernment.moa.id.opemsaml.MOAKeyStoreX509CredentialAdapter; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.KeyStoreUtils; +import at.gv.egovernment.moa.util.MiscUtil; + +public abstract class AbstractCredentialProvider { + + private static KeyStore keyStore = null; + + /** + * Get a friendlyName for this keyStore implementation + * This friendlyName is used for logging + * + * @return keyStore friendlyName + */ + public abstract String getFriendlyName(); + + /** + * Get KeyStore + * + * @return URL to the keyStore + */ + public abstract String getKeyStoreFilePath(); + + /** + * Get keyStore password + * + * @return Password of the keyStore + */ + public abstract String getKeyStorePassword(); + + /** + * Get alias of key for metadata signing + * + * @return key alias + */ + public abstract String getMetadataKeyAlias(); + + /** + * Get password of key for metadata signing + * + * @return key password + */ + public abstract String getMetadataKeyPassword(); + + /** + * Get alias of key for request/response signing + * + * @return key alias + */ + public abstract String getSignatureKeyAlias(); + + /** + * Get password of key for request/response signing + * + * @return key password + */ + public abstract String getSignatureKeyPassword(); + + /** + * Get alias of key for IDP response encryption + * + * @return key alias + */ + public abstract String getEncryptionKeyAlias(); + + /** + * Get password of key for IDP response encryption + * + * @return key password + */ + public abstract String getEncryptionKeyPassword(); + + + public X509Credential getIDPMetaDataSigningCredential() + throws CredentialsNotAvailableException { + try { + + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( + keyStore, getMetadataKeyAlias(), getMetadataKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.SIGNING); + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + Logger.error(getFriendlyName() + " Metadata Signing credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException(getFriendlyName() + " Assertion Signing credentials (Alias: " + + getMetadataKeyAlias() + ") is not found or contains no PrivateKey.", null); + + } + return credentials; + } catch (Exception e) { + Logger.error("Failed to generate " + getFriendlyName() + " Metadata Signing credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException(e.getMessage(), null); + } + } + + public X509Credential getIDPAssertionSigningCredential() + throws CredentialsNotAvailableException { + try { + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( + keyStore, getSignatureKeyAlias(), getSignatureKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.SIGNING); + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + Logger.error(getFriendlyName() + " Assertion Signing credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException(getFriendlyName() + " Assertion Signing credentials (Alias: " + + getSignatureKeyAlias() + ") is not found or contains no PrivateKey.", null); + + } + + return (X509Credential) credentials; + } catch (Exception e) { + Logger.error("Failed to generate " + getFriendlyName() + " Assertion Signing credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException(e.getMessage(), null); + } + } + + public X509Credential getIDPAssertionEncryptionCredential() + throws CredentialsNotAvailableException { + try { + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + //if no encryption key is configured return null + if (MiscUtil.isEmpty(getEncryptionKeyAlias())) + return null; + + MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( + keyStore, getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.ENCRYPTION); + + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + Logger.error(getFriendlyName() + " Assertion Encryption credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException(getFriendlyName() + " Assertion Encryption credentials (Alias: " + + getEncryptionKeyAlias() + ") is not found or contains no PrivateKey.", null); + + } + + return (X509Credential) credentials; + } catch (Exception e) { + Logger.error("Failed to generate " + getFriendlyName() + " Assertion Encryption credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException(e.getMessage(), null); + } + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/CredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/CredentialProvider.java deleted file mode 100644 index d76e6c2f1..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/CredentialProvider.java +++ /dev/null @@ -1,198 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package at.gv.egovernment.moa.id.protocols.pvp2x.signer; - -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.interfaces.RSAPrivateKey; - -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.x509.BasicX509Credential; -import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.Signature; -import org.opensaml.xml.signature.SignatureConstants; - -import at.gv.egovernment.moa.id.opemsaml.MOAKeyStoreX509CredentialAdapter; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.util.KeyStoreUtils; -import at.gv.egovernment.moa.util.MiscUtil; - -public class CredentialProvider { - - private static KeyStore keyStore = null; - - public static X509Credential getIDPMetaDataSigningCredential() - throws CredentialsNotAvailableException { - PVPConfiguration config = PVPConfiguration.getInstance(); - try { - - if (keyStore == null) - keyStore = KeyStoreUtils.loadKeyStore(config.getIDPKeyStoreFilename(), - config.getIDPKeyStorePassword()); - - MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( - keyStore, config.getIDPKeyAliasMetadata(), config - .getIDPKeyPasswordMetadata().toCharArray()); - - credentials.setUsageType(UsageType.SIGNING); - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - Logger.error("IDP Metadata Signing credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("IDP Assertion Signing credentials (Alias: " - + config.getIDPKeyAliasMetadata() + ") is not found or contains no PrivateKey.", null); - - } - return credentials; - } catch (Exception e) { - Logger.error("Failed to generate IDP Metadata Signing credentials"); - e.printStackTrace(); - throw new CredentialsNotAvailableException(e.getMessage(), null); - } - } - - public static X509Credential getIDPAssertionSigningCredential() - throws CredentialsNotAvailableException { - PVPConfiguration config = PVPConfiguration.getInstance(); - try { - if (keyStore == null) - keyStore = KeyStoreUtils.loadKeyStore(config.getIDPKeyStoreFilename(), - config.getIDPKeyStorePassword()); - - MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( - keyStore, config.getIDPKeyAliasAssertionSign(), config - .getIDPKeyPasswordAssertionSign().toCharArray()); - - credentials.setUsageType(UsageType.SIGNING); - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - Logger.error("IDP Assertion Signing credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("IDP Assertion Signing credentials (Alias: " - + config.getIDPKeyAliasAssertionSign() + ") is not found or contains no PrivateKey.", null); - - } - - return (X509Credential) credentials; - } catch (Exception e) { - Logger.error("Failed to generate IDP Assertion Signing credentials"); - e.printStackTrace(); - throw new CredentialsNotAvailableException(e.getMessage(), null); - } - } - - public static X509Credential getIDPAssertionEncryptionCredential() - throws CredentialsNotAvailableException { - PVPConfiguration config = PVPConfiguration.getInstance(); - try { - if (keyStore == null) - keyStore = KeyStoreUtils.loadKeyStore(config.getIDPKeyStoreFilename(), - config.getIDPKeyStorePassword()); - - //if no encryption key is configured return null - if (MiscUtil.isEmpty(config.getIDPKeyAliasAssertionEncryption())) - return null; - - MOAKeyStoreX509CredentialAdapter credentials = new MOAKeyStoreX509CredentialAdapter( - keyStore, config.getIDPKeyAliasAssertionEncryption(), config - .getIDPKeyPasswordAssertionEncryption().toCharArray()); - - credentials.setUsageType(UsageType.ENCRYPTION); - - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - Logger.error("IDP Assertion Encryption credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("IDP Assertion Encryption credentials (Alias: " - + config.getIDPKeyAliasAssertionEncryption() + ") is not found or contains no PrivateKey.", null); - - } - - return (X509Credential) credentials; - } catch (Exception e) { - Logger.error("Failed to generate IDP Assertion Encryption credentials"); - e.printStackTrace(); - throw new CredentialsNotAvailableException(e.getMessage(), null); - } - } - - public static Signature getIDPSignature(Credential credentials) { - - PrivateKey privatekey = credentials.getPrivateKey(); - - Signature signer = SAML2Utils.createSAMLObject(Signature.class); - - if (privatekey instanceof RSAPrivateKey) { - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); - - } else if (privatekey instanceof iaik.security.ecc.ecdsa.ECPrivateKey) { - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); - - } else { - Logger.warn("Could NOT evaluate the Private-Key type from PVP credential."); - - } - - signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); - signer.setSigningCredential(credentials); - return signer; - - } - - public static Credential getSPTrustedCredential(String entityID) - throws CredentialsNotAvailableException { - - iaik.x509.X509Certificate cert = PVPConfiguration.getInstance() - .getTrustEntityCertificate(entityID); - - if (cert == null) { - throw new CredentialsNotAvailableException("ServiceProvider Certificate can not be loaded from Database", null); - } - - BasicX509Credential credential = new BasicX509Credential(); - credential.setEntityId(entityID); - credential.setUsageType(UsageType.SIGNING); - credential.setPublicKey(cert.getPublicKey()); - - return credential; - } - /* - * public static Credential getTrustedCredential() throws - * CredentialsNotAvailableException { String filename = - * PVPConfiguration.getInstance().getTrustEntityCertificate("sp.crt"); - * - * iaik.x509.X509Certificate cert; try { cert = new X509Certificate(new - * FileInputStream(new File(filename))); } catch (CertificateException e) { - * e.printStackTrace(); throw new - * CredentialsNotAvailableException(e.getMessage(), null); } catch - * (FileNotFoundException e) { e.printStackTrace(); throw new - * CredentialsNotAvailableException(e.getMessage(), null); } catch - * (IOException e) { e.printStackTrace(); throw new - * CredentialsNotAvailableException(e.getMessage(), null); } - * - * BasicX509Credential credential = new BasicX509Credential(); - * credential.setEntityId("sp.crt"); - * credential.setUsageType(UsageType.SIGNING); - * credential.setPublicKey(cert.getPublicKey()); - * - * return credential; } - */ -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/IDPCredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/IDPCredentialProvider.java new file mode 100644 index 000000000..8fb4ec3cf --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/IDPCredentialProvider.java @@ -0,0 +1,150 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.signer; + +import java.util.Properties; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import at.gv.egovernment.moa.id.config.auth.AuthConfiguration; +import at.gv.egovernment.moa.util.FileUtils; + +@Service("IDPCredentialProvider") +public class IDPCredentialProvider extends AbstractCredentialProvider { + public static final String IDP_JAVAKEYSTORE = "idp.ks.file"; + public static final String IDP_KS_PASS = "idp.ks.kspassword"; + + public static final String IDP_KEYALIASMETADATA = "idp.ks.metadata.alias"; + public static final String IDP_KEY_PASSMETADATA = "idp.ks.metadata.keypassword"; + + public static final String IDP_KEYALIASASSERTION = "idp.ks.assertion.sign.alias"; + public static final String IDP_KEY_PASSASSERTION = "idp.ks.assertion.sign.keypassword"; + + public static final String IDP_KEYALIASENCRYTPION = "sp.ks.assertion.encryption.alias"; + public static final String IDP_KEY_PASSENCRYTPION = "sp.ks.assertion.encryption.keypassword"; + + + private @Autowired AuthConfiguration authConfig; + private Properties props = null; + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getKeyStoreFilePath() + */ + @Override + public String getKeyStoreFilePath() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return FileUtils.makeAbsoluteURL( + props.getProperty(IDP_JAVAKEYSTORE), + authConfig.getRootConfigFileDir()); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getKeyStorePassword() + */ + @Override + public String getKeyStorePassword() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KS_PASS).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getMetadataKeyAlias() + */ + @Override + public String getMetadataKeyAlias() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEYALIASMETADATA).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getMetadataKeyPassword() + */ + @Override + public String getMetadataKeyPassword() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEY_PASSMETADATA).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getSignatureKeyAlias() + */ + @Override + public String getSignatureKeyAlias() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEYALIASASSERTION).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getSignatureKeyPassword() + */ + @Override + public String getSignatureKeyPassword() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEY_PASSASSERTION).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getEncryptionKeyAlias() + */ + @Override + public String getEncryptionKeyAlias() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEYALIASENCRYTPION).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getEncryptionKeyPassword() + */ + @Override + public String getEncryptionKeyPassword() { + if (props == null) + props = authConfig.getGeneralPVP2ProperiesConfig(); + + return props.getProperty(IDP_KEYALIASENCRYTPION).trim(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider#getCredentialName() + */ + @Override + public String getFriendlyName() { + return "IDP"; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/MOASAMLSOAPClient.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/MOASAMLSOAPClient.java index 4d12c38da..75ef7e5a1 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/MOASAMLSOAPClient.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/MOASAMLSOAPClient.java @@ -57,6 +57,15 @@ public class MOASAMLSOAPClient { BasicSOAPMessageContext soapContext = new BasicSOAPMessageContext(); soapContext.setOutboundMessage(soapRequest); + + //set security policy context +// BasicSecurityPolicy policy = new BasicSecurityPolicy(); +// policy.getPolicyRules().add( +// new MOAPVPSignedRequestPolicyRule( +// TrustEngineFactory.getSignatureKnownKeysTrustEngine(), +// SPSSODescriptor.DEFAULT_ELEMENT_NAME)); +// SecurityPolicyResolver secResolver = new StaticSecurityPolicyResolver(policy); +// soapContext.setSecurityPolicyResolver(secResolver); HttpClientBuilder clientBuilder = new HttpClientBuilder(); if (destination.startsWith("https")) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/AbstractRequestSignedSecurityPolicyRule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/AbstractRequestSignedSecurityPolicyRule.java new file mode 100644 index 000000000..f62410656 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/AbstractRequestSignedSecurityPolicyRule.java @@ -0,0 +1,187 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.validation; + +import javax.xml.namespace.QName; +import javax.xml.transform.dom.DOMSource; +import javax.xml.validation.Schema; +import javax.xml.validation.Validator; + +import org.opensaml.common.SignableSAMLObject; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.common.xml.SAMLSchemaBuilder; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.ws.message.MessageContext; +import org.opensaml.ws.security.SecurityPolicyException; +import org.opensaml.ws.security.SecurityPolicyRule; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.validation.ValidationException; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SchemaValidationException; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public abstract class AbstractRequestSignedSecurityPolicyRule implements SecurityPolicyRule { + + private SignatureTrustEngine trustEngine = null; + private QName peerEntityRole = null; + /** + * @param peerEntityRole + * + */ + public AbstractRequestSignedSecurityPolicyRule(SignatureTrustEngine trustEngine, QName peerEntityRole) { + this.trustEngine = trustEngine; + this.peerEntityRole = peerEntityRole; + + } + + + /** + * Reload the PVP metadata for a given entity + * + * @param entityID for which the metadata should be refreshed. + * @return true if the refresh was successful, otherwise false + */ + protected abstract boolean refreshMetadataProvider(String entityID); + + + protected abstract SignableSAMLObject getSignedSAMLObject(XMLObject inboundData); + + /* (non-Javadoc) + * @see org.opensaml.ws.security.SecurityPolicyRule#evaluate(org.opensaml.ws.message.MessageContext) + */ + @Override + public void evaluate(MessageContext context) throws SecurityPolicyException { + try { + verifySignature(context); + + } catch (SecurityPolicyException e) { + if (MiscUtil.isEmpty(context.getInboundMessageIssuer())) { + throw e; + + } + Logger.debug("PVP2X message validation FAILED. Reload metadata for entityID: " + context.getInboundMessageIssuer()); + if (!refreshMetadataProvider(context.getInboundMessageIssuer())) + throw e; + + else { + Logger.trace("PVP2X metadata reload finished. Check validate message again."); + verifySignature(context); + + } + Logger.trace("Second PVP2X message validation finished"); + + } + + + } + + private void verifySignature(MessageContext context) throws SecurityPolicyException { + SignableSAMLObject samlObj = getSignedSAMLObject(context.getInboundMessage()); + if (samlObj != null && samlObj.getSignature() != null) { + + SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + performSchemaValidation(samlObj.getDOM()); + + } catch (ValidationException e) { + Logger.warn("Signature is not conform to SAML signature profile", e); + throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); + + } catch (SchemaValidationException e) { + Logger.warn("Signature is not conform to SAML signature profile", e); + throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); + + } + + + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add( new EntityIDCriteria(context.getInboundMessageIssuer()) ); + criteriaSet.add( new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS) ); + criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); + + try { + if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new SecurityPolicyException("Signature validation FAILED."); + + } + Logger.debug("PVP AuthnRequest signature valid."); + + } catch (org.opensaml.xml.security.SecurityException e) { + Logger.info("PVP2x message signature validation FAILED. Message:" + e.getMessage()); + throw new SecurityPolicyException("Signature validation FAILED."); + + } + + } else { + throw new SecurityPolicyException("Request is not signed."); + + } + + } + + private void performSchemaValidation(Element source) throws SchemaValidationException { + + String err = null; + try { + Schema test = SAMLSchemaBuilder.getSAML11Schema(); + Validator val = test.newValidator(); + val.validate(new DOMSource(source)); + Logger.debug("Schema validation check done OK"); + return; + + } catch (SAXException e) { + err = e.getMessage(); + if (Logger.isDebugEnabled() || Logger.isTraceEnabled()) + Logger.warn("Schema validation FAILED with exception:", e); + else + Logger.warn("Schema validation FAILED with message: "+ e.getMessage()); + + } catch (Exception e) { + err = e.getMessage(); + if (Logger.isDebugEnabled() || Logger.isTraceEnabled()) + Logger.warn("Schema validation FAILED with exception:", e); + else + Logger.warn("Schema validation FAILED with message: "+ e.getMessage()); + + } + + throw new SchemaValidationException("pvp2.22", new Object[]{err}); + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/MOAPVPSignedRequestPolicyRule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/MOAPVPSignedRequestPolicyRule.java new file mode 100644 index 000000000..932f3b818 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/validation/MOAPVPSignedRequestPolicyRule.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.pvp2x.validation; + +import javax.xml.namespace.QName; + +import org.opensaml.common.SignableSAMLObject; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.SignatureTrustEngine; + +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; + +/** + * @author tlenz + * + */ +public class MOAPVPSignedRequestPolicyRule extends + AbstractRequestSignedSecurityPolicyRule { + + /** + * @param trustEngine + * @param peerEntityRole + */ + public MOAPVPSignedRequestPolicyRule(SignatureTrustEngine trustEngine, + QName peerEntityRole) { + super(trustEngine, peerEntityRole); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#refreshMetadataProvider(java.lang.String) + */ + @Override + protected boolean refreshMetadataProvider(String entityID) { + return MOAMetadataProvider.getInstance().refreshMetadataProvider(entityID); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#getSignedSAMLObject(org.opensaml.xml.XMLObject) + */ + @Override + protected SignableSAMLObject getSignedSAMLObject(XMLObject inboundData) { + if (inboundData instanceof SignableSAMLObject) + return (SignableSAMLObject) inboundData; + + else + return null; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java index 69c760f19..4650327b4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java @@ -29,6 +29,8 @@ import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.security.SAMLSignatureProfileValidator; import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.x509.BasicX509Credential; import org.opensaml.xml.signature.SignatureValidator; import org.opensaml.xml.validation.ValidationException; @@ -37,9 +39,10 @@ import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoCredentialsException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SAMLRequestNotSignedException; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.MiscUtil; @@ -83,8 +86,7 @@ public class EntityVerifier { throw new SAMLRequestNotSignedException(e); } - Credential credential = CredentialProvider - .getSPTrustedCredential(entityDescriptor.getEntityID()); + Credential credential = getSPTrustedCredential(entityDescriptor.getEntityID()); if (credential == null) { throw new NoCredentialsException(entityDescriptor.getEntityID()); } @@ -171,8 +173,7 @@ public class EntityVerifier { + " entryID is used to select the certificate to perform Metadata verification."); } - Credential credential = CredentialProvider - .getSPTrustedCredential(entities.get(0).getEntityID()); + Credential credential = getSPTrustedCredential(entities.get(0).getEntityID()); if (credential == null) { throw new NoCredentialsException("moaID IDP"); @@ -188,5 +189,23 @@ public class EntityVerifier { } } } + + public static Credential getSPTrustedCredential(String entityID) + throws CredentialsNotAvailableException { + + iaik.x509.X509Certificate cert = PVPConfiguration.getInstance() + .getTrustEntityCertificate(entityID); + + if (cert == null) { + throw new CredentialsNotAvailableException("ServiceProvider Certificate can not be loaded from Database", null); + } + + BasicX509Credential credential = new BasicX509Credential(); + credential.setEntityId(entityID); + credential.setUsageType(UsageType.SIGNING); + credential.setPublicKey(cert.getPublicKey()); + + return credential; + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java index 70b778c49..5e44c9057 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java @@ -25,6 +25,7 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.verification; import java.util.ArrayList; import java.util.List; +import javax.xml.namespace.QName; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; @@ -49,32 +50,34 @@ import org.opensaml.xml.encryption.DecryptionException; import org.opensaml.xml.encryption.InlineEncryptedKeyResolver; import org.opensaml.xml.encryption.SimpleRetrievalMethodEncryptedKeyResolver; import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.criteria.EntityIDCriteria; import org.opensaml.xml.security.criteria.UsageCriteria; import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver; -import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.signature.SignatureTrustEngine; import org.opensaml.xml.validation.ValidationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import org.w3c.dom.Element; import org.xml.sax.SAXException; import at.gv.egovernment.moa.id.auth.exception.InvalidProtocolRequestException; import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; +import at.gv.egovernment.moa.id.config.auth.AuthConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionValidationExeption; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SchemaValidationException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; 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.metadata.MOAMetadataProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; -import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; +@Service("SAMLVerificationEngine") public class SAMLVerificationEngine { - + + @Autowired AuthConfiguration authConfig; public void verify(InboundMessage msg, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { try { @@ -83,7 +86,7 @@ public class SAMLVerificationEngine { verifyRequest(((RequestAbstractType)((MOARequest)msg).getSamlRequest()), sigTrustEngine); else - verifyResponse(((MOAResponse)msg).getResponse(), sigTrustEngine); + verifyIDPResponse(((MOAResponse)msg).getResponse(), sigTrustEngine); } catch (InvalidProtocolRequestException e) { if (MiscUtil.isEmpty(msg.getEntityID())) { @@ -102,15 +105,24 @@ public class SAMLVerificationEngine { verifyRequest(((RequestAbstractType)((MOARequest)msg).getSamlRequest()), sigTrustEngine); else - verifyResponse(((MOAResponse)msg).getResponse(), sigTrustEngine); + verifyIDPResponse(((MOAResponse)msg).getResponse(), sigTrustEngine); } Logger.trace("Second PVP2X message validation finished"); } } + public void verifyIDPResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException{ + verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + + } - public void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException{ + public void verifySLOResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException { + verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME); + + } + + private void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine, QName defaultElementName) throws InvalidProtocolRequestException{ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); try { profileValidator.validate(samlObj.getSignature()); @@ -127,7 +139,7 @@ public class SAMLVerificationEngine { CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) ); - criteriaSet.add( new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); + criteriaSet.add( new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS) ); criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); try { @@ -170,15 +182,25 @@ public class SAMLVerificationEngine { } } - public static void validateAssertion(Response samlResp, boolean validateDestination) throws AssertionValidationExeption { + public void validateAssertion(Response samlResp, boolean validateDestination, Credential assertionDecryption) throws AssertionValidationExeption { try { if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { List<org.opensaml.saml2.core.Assertion> saml2assertions = new ArrayList<org.opensaml.saml2.core.Assertion>(); - if (validateDestination && !samlResp.getDestination().startsWith( - PVPConfiguration.getInstance().getIDPPublicPath())) { + //validate destination URL + List<String> allowedPublicURLPrefix = authConfig.getPublicURLPrefix(); + boolean isValidDestination = false; + for (String allowedPreFix : allowedPublicURLPrefix) { + if (validateDestination && samlResp.getDestination().startsWith( + allowedPreFix)) { + isValidDestination = true; + break; + + } + } + if (!isValidDestination && validateDestination) { Logger.warn("PVP 2.1 assertion destination does not match to IDP URL"); - throw new AssertionValidationExeption("PVP 2.1 assertion destination does not match to IDP URL", null); + throw new AssertionValidationExeption("PVP 2.1 assertion destination does not match to IDP URL", null); } @@ -188,11 +210,9 @@ public class SAMLVerificationEngine { //decrypt assertions Logger.debug("Found encryped assertion. Start decryption ..."); - - X509Credential authDecCredential = CredentialProvider.getIDPAssertionEncryptionCredential(); - + StaticKeyInfoCredentialResolver skicr = - new StaticKeyInfoCredentialResolver(authDecCredential); + new StaticKeyInfoCredentialResolver(assertionDecryption); ChainingEncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver(); encryptedKeyResolver.getResolverChain().add( new InlineEncryptedKeyResolver() ); @@ -256,10 +276,6 @@ public class SAMLVerificationEngine { + samlResp.getStatus().getStatusCode().getValue(), null); } - } catch (CredentialsNotAvailableException e) { - Logger.warn("Assertion decrypt FAILED - No Credentials", e); - throw new AssertionValidationExeption("Assertion decrypt FAILED - No Credentials", null, e); - } catch (DecryptionException e) { Logger.warn("Assertion decrypt FAILED.", e); throw new AssertionValidationExeption("Assertion decrypt FAILED.", null, e); @@ -269,7 +285,7 @@ public class SAMLVerificationEngine { } } - private static void performSchemaValidation(Element source) throws SchemaValidationException { + private void performSchemaValidation(Element source) throws SchemaValidationException { String err = null; try { |