diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth')
56 files changed, 7762 insertions, 0 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java new file mode 100644 index 000000000..5f4ec2d29 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java @@ -0,0 +1,1019 @@ +package at.gv.egovernment.moa.id.auth; + +import iaik.pki.PKIException; +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import javax.xml.transform.TransformerException; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; +import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataAssertionBuilder; +import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.builder.CertInfoVerifyXMLSignatureRequestBuilder; +import at.gv.egovernment.moa.id.auth.builder.CreateXMLSignatureRequestBuilder; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.builder.GetIdentityLinkFormBuilder; +import at.gv.egovernment.moa.id.auth.builder.InfoboxReadRequestBuilder; +import at.gv.egovernment.moa.id.auth.builder.InfoboxValidatorParamsBuilder; +import at.gv.egovernment.moa.id.auth.builder.PersonDataBuilder; +import at.gv.egovernment.moa.id.auth.builder.SAMLArtifactBuilder; +import at.gv.egovernment.moa.id.auth.builder.SelectBKUFormBuilder; +import at.gv.egovernment.moa.id.auth.builder.VerifyXMLSignatureRequestBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult; +import at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams; +import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; +import at.gv.egovernment.moa.id.auth.parser.CreateXMLSignatureResponseParser; +import at.gv.egovernment.moa.id.auth.parser.ExtendedInfoboxReadResponseParser; +import at.gv.egovernment.moa.id.auth.parser.InfoboxReadResponseParser; +import at.gv.egovernment.moa.id.auth.parser.SAMLArtifactParser; +import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; +import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; +import at.gv.egovernment.moa.id.auth.validator.CreateXMLSignatureResponseValidator; +import at.gv.egovernment.moa.id.auth.validator.IdentityLinkValidator; +import at.gv.egovernment.moa.id.auth.validator.InfoboxValidator; +import at.gv.egovernment.moa.id.auth.validator.ValidateException; +import at.gv.egovernment.moa.id.auth.validator.VerifyXMLSignatureResponseValidator; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameter; +import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameters; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.BoolUtils; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.DateTimeUtils; +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * API for MOA ID Authentication Service.<br> + * {@link AuthenticationSession} is stored in a session store and retrieved + * by giving the session ID. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationServer implements MOAIDAuthConstants { + + /** single instance */ + private static AuthenticationServer instance; + /** session data store (session ID -> AuthenticationSession) */ + private static Map sessionStore = new HashMap(); + /** authentication data store (assertion handle -> AuthenticationData) */ + private static Map authenticationDataStore = new HashMap(); + /** + * time out in milliseconds used by {@link cleanup} for session store + */ + private long sessionTimeOut = 10 * 60 * 1000; // default 10 minutes + /** + * time out in milliseconds used by {@link cleanup} for authentication data store + */ + private long authDataTimeOut = 2 * 60 * 1000; // default 2 minutes + + /** + * Returns the single instance of <code>AuthenticationServer</code>. + * + * @return the single instance of <code>AuthenticationServer</code> + */ + public static AuthenticationServer getInstance() { + if (instance == null) + instance = new AuthenticationServer(); + return instance; + } + /** + * Constructor for AuthenticationServer. + */ + public AuthenticationServer() { + super(); + } + /** + * Processes request to select a BKU. + * <br/>Processing depends on value of {@link AuthConfigurationProvider#getBKUSelectionType}. + * <br/>For <code>bkuSelectionType==HTMLComplete</code>, a <code>returnURI</code> for the + * "BKU Auswahl" service is returned. + * <br/>For <code>bkuSelectionType==HTMLSelect</code>, an HTML form for BKU selection is returned. + * @param authURL base URL of MOA-ID Auth component + * @param target "Geschäftsbereich" + * @param oaURL online application URL requested + * @param bkuSelectionTemplateURL template for BKU selection form to be used + * in case of <code>HTMLSelect</code>; may be null + * @param templateURL URL providing an HTML template for the HTML form to be used + * for call <code>startAuthentication</code> + * @return for <code>bkuSelectionType==HTMLComplete</code>, the <code>returnURI</code> for the + * "BKU Auswahl" service; + * for <code>bkuSelectionType==HTMLSelect</code>, an HTML form for BKU selection + * @throws WrongParametersException upon missing parameters + * @throws AuthenticationException when the configured BKU selection service cannot be reached, + * and when the given bkuSelectionTemplateURL cannot be reached + * @throws ConfigurationException on missing configuration data + * @throws BuildException while building the HTML form + */ + public String selectBKU( + String authURL, + String target, + String oaURL, + String bkuSelectionTemplateURL, + String templateURL) + throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { + + //check if HTTP Connection may be allowed (through FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) + String boolStr = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter( + AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); + if ((!authURL.startsWith("https:")) && (false == BoolUtils.valueOf(boolStr))) + throw new AuthenticationException("auth.07", new Object[] { authURL + "*" }); + if (isEmpty(authURL)) + throw new WrongParametersException("StartAuthentication", "AuthURL"); + if (isEmpty(oaURL)) + throw new WrongParametersException("StartAuthentication", PARAM_OA); + + ConnectionParameter bkuConnParam = + AuthConfigurationProvider.getInstance().getBKUConnectionParameter(); + if (bkuConnParam == null) + throw new ConfigurationException( + "config.08", + new Object[] { "BKUSelection/ConnectionParameter" }); + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { oaURL }); + + if (!oaParam.getBusinessService()) { + if (isEmpty(target)) + throw new WrongParametersException("StartAuthentication", PARAM_TARGET); + } else { + if (!isEmpty(target)) { + Logger.info("Ignoring target parameter thus application type is \"businessService\""); + } + target = null; + } + + AuthenticationSession session = newSession(); + Logger.info("MOASession " + session.getSessionID() + " angelegt"); + session.setTarget(target); + session.setOAURLRequested(oaURL); + session.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); + session.setAuthURL(authURL); + session.setTemplateURL(templateURL); + session.setBusinessService(oaParam.getBusinessService()); + String returnURL = + new DataURLBuilder().buildDataURL(authURL, REQ_START_AUTHENTICATION, session.getSessionID()); + String bkuSelectionType = AuthConfigurationProvider.getInstance().getBKUSelectionType(); + if (bkuSelectionType.equals(AuthConfigurationProvider.BKU_SELECTION_TYPE_HTMLCOMPLETE)) { + // bkuSelectionType==HTMLComplete + String redirectURL = bkuConnParam.getUrl() + "?" + AuthServlet.PARAM_RETURN + "=" + returnURL; + return redirectURL; + } else { + // bkuSelectionType==HTMLSelect + String bkuSelectTag; + try { + bkuSelectTag = readBKUSelectTag(AuthConfigurationProvider.getInstance(), bkuConnParam); + } catch (Throwable ex) { + throw new AuthenticationException( + "auth.11", + new Object[] { bkuConnParam.getUrl(), ex.toString()}, + ex); + } + String bkuSelectionTemplate = null; + // override template url by url from configuration file + if (oaParam.getBkuSelectionTemplateURL() != null) { + bkuSelectionTemplateURL = oaParam.getBkuSelectionTemplateURL(); + } + if (bkuSelectionTemplateURL != null) { + try { + bkuSelectionTemplate = new String(FileUtils.readURL(bkuSelectionTemplateURL)); + } catch (IOException ex) { + throw new AuthenticationException( + "auth.03", + new Object[] { bkuSelectionTemplateURL, ex.toString()}, + ex); + } + } + String htmlForm = + new SelectBKUFormBuilder().build(bkuSelectionTemplate, returnURL, bkuSelectTag); + return htmlForm; + } + } + /** + * Method readBKUSelectTag. + * @param conf the ConfigurationProvider + * @param connParam the ConnectionParameter for that connection + * @return String + * @throws ConfigurationException on config-errors + * @throws PKIException on PKI errors + * @throws IOException on any data error + * @throws GeneralSecurityException on security errors + */ + private String readBKUSelectTag(ConfigurationProvider conf, ConnectionParameter connParam) + throws ConfigurationException, PKIException, IOException, GeneralSecurityException { + + if (connParam.isHTTPSURL()) + return SSLUtils.readHttpsURL(conf, connParam); + else + return HTTPUtils.readHttpURL(connParam.getUrl()); + } + /** + * Processes the beginning of an authentication session. + * <ul> + * <li>Starts an authentication session</li> + * <li>Creates an <code><InfoboxReadRequest></code></li> + * <li>Creates an HTML form for querying the identity link from the + * security layer implementation. + * <br>Form parameters include + * <ul> + * <li>the <code><InfoboxReadRequest></code></li> + * <li>the data URL where the security layer implementation sends it response to</li> + * </ul> + * </ul> + * @param authURL URL of the servlet to be used as data URL + * @param target "Geschäftsbereich" of the online application requested + * @param oaURL online application URL requested + * @param bkuURL URL of the "Bürgerkartenumgebung" to be used; + * may be <code>null</code>; in this case, the default location will be used + * @param templateURL URL providing an HTML template for the HTML form generated + * @return HTML form + * @throws AuthenticationException + * @see GetIdentityLinkFormBuilder + * @see InfoboxReadRequestBuilder + */ + public String startAuthentication( + String authURL, + String target, + String oaURL, + String templateURL, + String bkuURL, + String sessionID) + throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { + + if (isEmpty(sessionID)) { + if (isEmpty(authURL)) + throw new WrongParametersException("StartAuthentication", "AuthURL"); + + //check if HTTP Connection may be allowed (through FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) + String boolStr = + AuthConfigurationProvider.getInstance().getGenericConfigurationParameter( + AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); + if ((!authURL.startsWith("https:")) && (false == BoolUtils.valueOf(boolStr))) + throw new AuthenticationException("auth.07", new Object[] { authURL + "*" }); + if (isEmpty(oaURL)) + throw new WrongParametersException("StartAuthentication", PARAM_OA); + } + AuthenticationSession session; + OAAuthParameter oaParam; + if (sessionID != null) { + session = getSession(sessionID); + oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + } else { + oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { oaURL }); + if (!oaParam.getBusinessService()) { + if (isEmpty(target)) + throw new WrongParametersException("StartAuthentication", PARAM_TARGET); + } else { + target = null; + } + session = newSession(); + Logger.info("MOASession " + session.getSessionID() + " angelegt"); + session.setTarget(target); + session.setOAURLRequested(oaURL); + session.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); + session.setAuthURL(authURL); + session.setTemplateURL(templateURL); + session.setBusinessService(oaParam.getBusinessService()); + } + // BKU URL has not been set yet, even if session already exists + if (bkuURL == null) { + bkuURL = DEFAULT_BKU; + } + session.setBkuURL(bkuURL); + String infoboxReadRequest = + new InfoboxReadRequestBuilder().build(oaParam.getSlVersion12(), + oaParam.getBusinessService(), + oaParam.getIdentityLinkDomainIdentifier()); + String dataURL = + new DataURLBuilder().buildDataURL( + session.getAuthURL(), + REQ_VERIFY_IDENTITY_LINK, + session.getSessionID()); + String template = null; + // override template url by url from configuration file + if (oaParam.getTemplateURL() != null) { + templateURL = oaParam.getTemplateURL(); + } else { + templateURL = session.getTemplateURL(); + } + if (templateURL != null) { + try { + template = new String(FileUtils.readURL(templateURL)); + } catch (IOException ex) { + throw new AuthenticationException( + "auth.03", + new Object[] { templateURL, ex.toString()}, + ex); + } + } + String pushInfobox = ""; + VerifyInfoboxParameters verifyInfoboxParameters = oaParam.getVerifyInfoboxParameters(); + if (verifyInfoboxParameters != null) { + pushInfobox = verifyInfoboxParameters.getPushInfobox(); + } + String certInfoRequest = new CertInfoVerifyXMLSignatureRequestBuilder().build(oaParam.getSlVersion12()); + String certInfoDataURL = + new DataURLBuilder().buildDataURL( + session.getAuthURL(), + REQ_START_AUTHENTICATION, + session.getSessionID()); + String htmlForm = + new GetIdentityLinkFormBuilder().build( + template, + bkuURL, + infoboxReadRequest, + dataURL, + certInfoRequest, + certInfoDataURL, + pushInfobox); + return htmlForm; + } + /** + * Processes an <code><InfoboxReadResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><InfoboxReadResponse></code></li> + * <li>Parses identity link enclosed in <code><InfoboxReadResponse></code></li> + * <li>Verifies identity link by calling the MOA SP component</li> + * <li>Checks certificate authority of identity link</li> + * <li>Stores identity link in the session</li> + * <li>Verifies all additional infoboxes returned from the BKU</li> + * <li>Creates an authentication block to be signed by the user</li> + * <li>Creates and returns a <code><CreateXMLSignatureRequest></code> + * containg the authentication block, meant to be returned to the + * security layer implementation</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param infoboxReadResponseParameters The parameters from the response returned from + * the BKU including the <code><InfoboxReadResponse></code> + * @return String representation of the <code><CreateXMLSignatureRequest></code> + */ + public String verifyIdentityLink(String sessionID, Map infoboxReadResponseParameters) + throws + AuthenticationException, + BuildException, + ParseException, + ConfigurationException, + ValidateException, + ServiceException { + + if (isEmpty(sessionID)) + throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_IDENTITY_LINK, PARAM_SESSIONID}); + + String xmlInfoboxReadResponse = (String)infoboxReadResponseParameters.get(PARAM_XMLRESPONSE); + if (isEmpty(xmlInfoboxReadResponse)) + throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_IDENTITY_LINK, PARAM_XMLRESPONSE}); + + AuthenticationSession session = getSession(sessionID); + if (session.getTimestampIdentityLink() != null) + throw new AuthenticationException("auth.01", new Object[] { sessionID }); + session.setTimestampIdentityLink(); + AuthConfigurationProvider authConf = AuthConfigurationProvider.getInstance(); + // parses the <InfoboxReadResponse> + IdentityLink identityLink = + new InfoboxReadResponseParser(xmlInfoboxReadResponse).parseIdentityLink(); + // validates the identity link + IdentityLinkValidator.getInstance().validate(identityLink); + // builds a <VerifyXMLSignatureRequest> for a call of MOA-SP + Element domVerifyXMLSignatureRequest = + new VerifyXMLSignatureRequestBuilder().build( + identityLink, + authConf.getMoaSpIdentityLinkTrustProfileID()); + + // invokes the call + Element domVerifyXMLSignatureResponse = + new SignatureVerificationInvoker().verifyXMLSignature(domVerifyXMLSignatureRequest); + // parses the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponse verifyXMLSignatureResponse = + new VerifyXMLSignatureResponseParser(domVerifyXMLSignatureResponse).parseData(); + + if (identityLink.getIdentificationType().equalsIgnoreCase(Constants.URN_PREFIX_BASEID)) { + } + + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + + // if OA is type is business service the manifest validation result has to be ignored + boolean ignoreManifestValidationResult = oaParam.getBusinessService() ? true : false; + + // validates the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponseValidator.getInstance().validate( + verifyXMLSignatureResponse, + authConf.getIdentityLinkX509SubjectNames(), + VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK, + ignoreManifestValidationResult); + + session.setIdentityLink(identityLink); + // now validate the extended infoboxes + verifyInfoboxes(session, infoboxReadResponseParameters, !oaParam.getProvideStammzahl()); + // builds the AUTH-block + String authBlock = buildAuthenticationBlock(session); +// session.setAuthBlock(authBlock); + // builds the <CreateXMLSignatureRequest> + String[] transformsInfos = oaParam.getTransformsInfos(); + if ((transformsInfos == null) || (transformsInfos.length == 0)) { + // no OA specific transforms specified, use default ones + transformsInfos = authConf.getTransformsInfos(); + } + String createXMLSignatureRequest = + new CreateXMLSignatureRequestBuilder().build(authBlock, + oaParam.getKeyBoxIdentifier(), + transformsInfos, + oaParam.getSlVersion12()); + return createXMLSignatureRequest; + } + /** + * Builds an authentication block <code><saml:Assertion></code> from given session data. + * @param session authentication session + * + * @return <code><saml:Assertion></code> as a String + * + * @throws BuildException If an error occurs on serializing an extended SAML attribute + * to be appended to the AUTH-Block. + */ + private String buildAuthenticationBlock(AuthenticationSession session) throws BuildException { + IdentityLink identityLink = session.getIdentityLink(); + String issuer = identityLink.getName(); + String gebDat = identityLink.getDateOfBirth(); + String identificationValue = identityLink.getIdentificationValue(); + String identificationType = identityLink.getIdentificationType(); + String issueInstant = DateTimeUtils.buildDateTime(Calendar.getInstance()); + session.setIssueInstant(issueInstant); + String authURL = session.getAuthURL(); + String target = session.getTarget(); + String oaURL = session.getPublicOAURLPrefix(); + List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); + String authBlock = new AuthenticationBlockAssertionBuilder().buildAuthBlock( + issuer, + issueInstant, + authURL, + target, + identificationValue, + identificationType, + oaURL, + gebDat, + extendedSAMLAttributes, + session); + + return authBlock; + } + + /** + * Verifies the infoboxes (except of the identity link infobox) returned by the BKU by + * calling appropriate validator classes. + * + * @param session The actual authentication session. + * @param infoboxReadResponseParams The parameters returned from the BKU as response + * to an infobox read request (including the infobox + * tokens to be verified). + * @param hideStammzahl Indicates whether source pins (<code>Stammzahl</code>en) + * should be hidden in any SAML attribute that may be + * returned by a validator. + * + * @throws AuthenticationException If the verification of at least one infobox fails. + * @throws ConfigurationException If the OAuthParameter cannot be extracted. + */ + private void verifyInfoboxes( + AuthenticationSession session, Map infoboxReadResponseParams, boolean hideStammzahl) + throws ValidateException, ConfigurationException + { + + AuthConfigurationProvider authConfigurationProvider = AuthConfigurationProvider.getInstance(); + // get the default VerifyInfobox parameters + Map defaultInfoboxParameters = null; + VerifyInfoboxParameters defaultVerifyInfoboxParameters = + authConfigurationProvider.getDefaultVerifyInfoboxParameters(); + if (defaultVerifyInfoboxParameters != null) { + defaultInfoboxParameters = defaultVerifyInfoboxParameters.getInfoboxParameters(); + } + // get the OA specific VerifyInfobox parameters + Map infoboxParameters = null; + OAAuthParameter oaParam = + authConfigurationProvider.getOnlineApplicationParameter(session.getPublicOAURLPrefix()); + VerifyInfoboxParameters verifyInfoboxParameters = oaParam.getVerifyInfoboxParameters(); + if (verifyInfoboxParameters != null) { + Vector authAttributes = new Vector(); + Vector oaAttributes = new Vector(); + infoboxParameters = verifyInfoboxParameters.getInfoboxParameters(); + // get the list of infobox identifiers + List identifiers = verifyInfoboxParameters.getIdentifiers(); + if (identifiers != null) { + // step through the identifiers and verify the infoboxes + Iterator it = identifiers.iterator(); + while (it.hasNext()) { + String identifier = (String)it.next(); + // get the infobox read response from the map of parameters + String infoboxReadResponse = (String)infoboxReadResponseParams.get(identifier); + // get the configuration parameters + VerifyInfoboxParameter verifyInfoboxParameter = null; + Object object = infoboxParameters.get(identifier); + // if not present, use default + if ((object == null) && (defaultInfoboxParameters != null)) { + object = defaultInfoboxParameters.get(identifier); + } + if (object != null) { + verifyInfoboxParameter = (VerifyInfoboxParameter)object; + } + if (infoboxReadResponse != null) { + if (verifyInfoboxParameter == null) { + // should not happen because of the pushinfobox mechanism; check it anyway + Logger.error("No validator for verifying \"" + identifier + "\"-infobox configured."); + throw new ValidateException("validator.41", new Object[] {identifier}); + } else { + String friendlyName = verifyInfoboxParameter.getFriendlyName(); + // get the class for validating the infobox + InfoboxValidator infoboxValidator = null; + try { + Class validatorClass = Class.forName(verifyInfoboxParameter.getValidatorClassName()); + infoboxValidator = (InfoboxValidator) validatorClass.newInstance(); + } catch (Exception e) { + Logger.error("Could not load validator class \"" + verifyInfoboxParameter.getValidatorClassName() + + "\" for \"" + identifier + "\"-infobox: " + e.getMessage()); + throw new ValidateException("validator.42", new Object[] {friendlyName}); + } + Logger.debug("Successfully loaded validator class \"" + verifyInfoboxParameter.getValidatorClassName() + + "\" for \"" + identifier + "\"-infobox."); + // parse the infobox read reponse + List infoboxTokenList = null; + try { + infoboxTokenList = + ExtendedInfoboxReadResponseParser.parseInfoboxReadResponse(infoboxReadResponse, friendlyName); + } catch (ParseException e) { + Logger.error("InfoboxReadResponse for \"" + identifier + + "\"-infobox could not be parsed successfully: " + e.getMessage()); + throw new ValidateException("validator.43", new Object[] {friendlyName}); + } + // build the parameters for validating the infobox + InfoboxValidatorParams infoboxValidatorParams = + InfoboxValidatorParamsBuilder.buildInfoboxValidatorParams( + session, verifyInfoboxParameter, infoboxTokenList, hideStammzahl); + // now validate the infobox + InfoboxValidationResult infoboxValidationResult = null; + try { + infoboxValidationResult = infoboxValidator.validate(infoboxValidatorParams); + } catch (ValidateException e) { + Logger.error("Error validating " + identifier + " infobox:" + e.getMessage()); + throw new ValidateException( + "validator.44", new Object[] {friendlyName}); + } + if (!infoboxValidationResult.isValid()) { + Logger.info("Validation of " + identifier + " infobox failed."); + throw new ValidateException( + "validator.40", new Object[] {friendlyName, infoboxValidationResult.getErrorMessage()}); + } + + Logger.info(identifier + " infobox successfully validated."); + + // get the SAML attributes to be appended to the AUTHBlock or to the final + // SAML Assertion + ExtendedSAMLAttribute[] extendedSAMLAttributes = infoboxValidationResult.getExtendedSamlAttributes(); + if (extendedSAMLAttributes != null) { + int length = extendedSAMLAttributes.length; + for (int i=0; i<length; i++) { + ExtendedSAMLAttribute samlAttribute = extendedSAMLAttributes[i]; + String name = samlAttribute.getName(); + if (name == null) { + Logger.info("The name of SAML-Attribute number " + (i+1) + " returned from " + + identifier + "-infobox validator is null."); + throw new ValidateException( + "validator.45", new Object[] {friendlyName, "Name", String.valueOf((i+1)), "null"}); + } + if (name == "") { + Logger.info("The name of SAML-Attribute number " + (i+1) + " returned from " + + identifier + "-infobox validator is empty."); + throw new ValidateException( + "validator.45", new Object[] {friendlyName, "Name", String.valueOf((i+1)), "leer"}); + } + if (samlAttribute.getNameSpace() == null) { + Logger.info("The namespace of SAML-Attribute number " + (i+1) + " returned from " + + identifier + "-infobox validator is null."); + throw new ValidateException( + "validator.45", new Object[] {friendlyName, "Namespace", String.valueOf((i+1)), "null"}); + } + Object value = samlAttribute.getValue(); + if (value == null) { + Logger.info("The value of SAML-Attribute number " + (i+1) + " returned from " + + identifier + "-infobox validator is null."); + throw new ValidateException( + "validator.45", new Object[] {friendlyName ,"Wert", String.valueOf((i+1)), "null"}); + } + if ((value instanceof String) || (value instanceof Element)) { + + switch (samlAttribute.getAddToAUTHBlock()) { + case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK: + authAttributes.add(samlAttribute); + oaAttributes.add(samlAttribute); + break; + case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY: + authAttributes.add(samlAttribute); + break; + case ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK: + oaAttributes.add(samlAttribute); + break; + default: + Logger.info("Invalid return value from method \"getAddToAUTHBlock()\" (" + + samlAttribute.getAddToAUTHBlock() + ") in SAML attribute number " + + (i+1) + " for infobox " + identifier); + throw new ValidateException( + "validator.47", new Object[] {friendlyName, String.valueOf((i+1))}); + } + } else { + Logger.info("The type of SAML-Attribute number " + (i+1) + " returned from " + + identifier + "-infobox validator is not valid. Must be either \"java.Lang.String\"" + + " or \"org.w3c.dom.Element\""); + throw new ValidateException( + "validator.46", new Object[] {identifier, String.valueOf((i+1))}); + + } + } + + } + } + } else { + if ((verifyInfoboxParameter !=null) && (verifyInfoboxParameter.isRequired())) { + Logger.info("Infobox \"" + identifier + "\" is required, but not returned from the BKU"); + throw new ValidateException( + "validator.48", new Object[] {verifyInfoboxParameter.getFriendlyName()}); + + } + Logger.debug("Infobox \"" + identifier + "\" not returned from BKU."); + } + } + session.setExtendedSAMLAttributesAUTH(authAttributes); + session.setExtendedSAMLAttributesOA(oaAttributes); + } + } + } + + /** + * Processes a <code><CreateXMLSignatureResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><CreateXMLSignatureResponse></code></li> + * <li>Parses <code><CreateXMLSignatureResponse></code> for error codes</li> + * <li>Parses authentication block enclosed in + * <code><CreateXMLSignatureResponse></code></li> + * <li>Verifies authentication block by calling the MOA SP component</li> + * <li>Creates authentication data</li> + * <li>Creates a corresponding SAML artifact</li> + * <li>Stores authentication data in the authentication data store + * indexed by the SAML artifact</li> + * <li>Deletes authentication session</li> + * <li>Returns the SAML artifact, encoded BASE64</li> + * </ul> + * + * @param sessionID session ID of the running authentication session + * @param xmlCreateXMLSignatureReadResponse String representation of the + * <code><CreateXMLSignatureResponse></code> + * @return SAML artifact needed for retrieving authentication data, encoded BASE64 + */ + public String verifyAuthenticationBlock( + String sessionID, + String xmlCreateXMLSignatureReadResponse) + throws + AuthenticationException, + BuildException, + ParseException, + ConfigurationException, + ServiceException, + ValidateException { + + if (isEmpty(sessionID)) + throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID}); + if (isEmpty(xmlCreateXMLSignatureReadResponse)) + throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); + AuthenticationSession session = getSession(sessionID); + AuthConfigurationProvider authConf = AuthConfigurationProvider.getInstance(); + // parses <CreateXMLSignatureResponse> + CreateXMLSignatureResponse csresp = + new CreateXMLSignatureResponseParser(xmlCreateXMLSignatureReadResponse).parseResponse(); + try { + String serializedAssertion = DOMUtils.serializeNode(csresp.getSamlAssertion()); + session.setAuthBlock(serializedAssertion); + } catch (TransformerException e) { + throw new ParseException("parser.04", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); + } catch (IOException e) { + throw new ParseException("parser.04", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); + } + // validates <CreateXMLSignatureResponse> + new CreateXMLSignatureResponseValidator().validate(csresp, session); + // builds a <VerifyXMLSignatureRequest> for a MOA-SPSS call + String[] vtids = authConf.getMoaSpAuthBlockVerifyTransformsInfoIDs(); + String tpid = authConf.getMoaSpAuthBlockTrustProfileID(); + Element domVsreq = new VerifyXMLSignatureRequestBuilder().build(csresp, vtids, tpid); + // debug output + + // invokes the call + Element domVsresp = new SignatureVerificationInvoker().verifyXMLSignature(domVsreq); + // debug output + + // parses the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponseParser(domVsresp).parseData(); + // validates the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponseValidator.getInstance().validate( + vsresp, + null, + VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, + false); + + + // TODO See Bug #144 + // Compare AuthBlock Data with information stored in session, especially date and time + + + // compares the public keys from the identityLink with the AuthBlock + VerifyXMLSignatureResponseValidator.getInstance().validateCertificate( + vsresp, + session.getIdentityLink()); + + // builds authentication data and stores it together with a SAML artifact + AuthenticationData authData = buildAuthenticationData(session, vsresp); + String samlArtifact = + new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID()); + storeAuthenticationData(samlArtifact, authData); + // invalidates the authentication session + sessionStore.remove(sessionID); + Logger.info( + "Anmeldedaten zu MOASession " + sessionID + " angelegt, SAML Artifakt " + samlArtifact); + return samlArtifact; + } + /** + * Builds the AuthenticationData object together with the + * corresponding <code><saml:Assertion></code> + * @param session authentication session + * @param verifyXMLSigResp VerifyXMLSignatureResponse from MOA-SP + * @return AuthenticationData object + * @throws ConfigurationException while accessing configuration data + * @throws BuildException while building the <code><saml:Assertion></code> + */ + private AuthenticationData buildAuthenticationData( + AuthenticationSession session, + VerifyXMLSignatureResponse verifyXMLSigResp) + throws ConfigurationException, BuildException { + + IdentityLink identityLink = session.getIdentityLink(); + AuthenticationData authData = new AuthenticationData(); + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + boolean businessService = oaParam.getBusinessService(); + authData.setMajorVersion(1); + authData.setMinorVersion(0); + authData.setAssertionID(Random.nextRandom()); + authData.setIssuer(session.getAuthURL()); + authData.setIssueInstant(DateTimeUtils.buildDateTime(Calendar.getInstance())); + + authData.setIdentificationType(identityLink.getIdentificationType()); + authData.setGivenName(identityLink.getGivenName()); + authData.setFamilyName(identityLink.getFamilyName()); + authData.setDateOfBirth(identityLink.getDateOfBirth()); + authData.setQualifiedCertificate(verifyXMLSigResp.isQualifiedCertificate()); + authData.setPublicAuthority(verifyXMLSigResp.isPublicAuthority()); + authData.setPublicAuthorityCode(verifyXMLSigResp.getPublicAuthorityCode()); + authData.setBkuURL(session.getBkuURL()); + boolean provideStammzahl = oaParam.getProvideStammzahl(); + if (provideStammzahl) { + authData.setIdentificationValue(identityLink.getIdentificationValue()); + } + String prPerson = new PersonDataBuilder().build(identityLink, provideStammzahl); + try { + String signerCertificateBase64 = ""; + if (oaParam.getProvideCertifcate()) { + X509Certificate signerCertificate = verifyXMLSigResp.getX509certificate(); + if (signerCertificate != null) { + signerCertificateBase64 = Base64Utils.encode(signerCertificate.getEncoded()); + } else { + Logger.info("\"provideCertificate\" is \"true\", but no signer certificate available"); + } + } + authData.setSignerCertificate(signerCertificateBase64); + if (businessService) { + authData.setWBPK(identityLink.getIdentificationValue()); + } else { + // only compute bPK if online applcation is a public service + String bpkBase64 = + new BPKBuilder().buildBPK( + identityLink.getIdentificationValue(), + session.getTarget()); + authData.setBPK(bpkBase64); + } + String ilAssertion = + oaParam.getProvideIdentityLink() + ? identityLink.getSerializedSamlAssertion() + : ""; + if (!oaParam.getProvideStammzahl()) { + ilAssertion = StringUtils.replaceAll(ilAssertion, identityLink.getIdentificationValue(), ""); + } + String authBlock = oaParam.getProvideAuthBlock() ? session.getAuthBlock() : ""; + String samlAssertion = + new AuthenticationDataAssertionBuilder().build( + authData, + prPerson, + authBlock, + ilAssertion, + session.getBkuURL(), + signerCertificateBase64, + businessService, + session.getExtendedSAMLAttributesOA()); + authData.setSamlAssertion(samlAssertion); + return authData; + } catch (Throwable ex) { + throw new BuildException( + "builder.00", + new Object[] { "AuthenticationData", ex.toString()}, + ex); + } + } + /** + * Retrieves <code>AuthenticationData</code> indexed by the SAML artifact. + * The <code>AuthenticationData</code> is deleted from the store upon end of this call. + * + * @return <code>AuthenticationData</code> + */ + public AuthenticationData getAuthenticationData(String samlArtifact) + throws AuthenticationException { + String assertionHandle; + try { + assertionHandle = new SAMLArtifactParser(samlArtifact).parseAssertionHandle(); + } catch (ParseException ex) { + throw new AuthenticationException("1205", new Object[] { samlArtifact, ex.toString()}); + } + AuthenticationData authData = null; + synchronized (authenticationDataStore) { + authData = (AuthenticationData) authenticationDataStore.get(assertionHandle); + if (authData == null) { + Logger.error("Assertion not found for SAML Artifact: " + samlArtifact); + throw new AuthenticationException("1206", new Object[] { samlArtifact }); + } + authenticationDataStore.remove(assertionHandle); + } + long now = new Date().getTime(); + if (now - authData.getTimestamp().getTime() > authDataTimeOut) + throw new AuthenticationException("1207", new Object[] { samlArtifact }); + Logger.debug("Assertion delivered for SAML Artifact: " + samlArtifact); + return authData; + } + /** + * Stores authentication data indexed by the assertion handle contained in the + * given saml artifact. + * @param samlArtifact SAML artifact + * @param authData authentication data + * @throws AuthenticationException when SAML artifact is invalid + */ + private void storeAuthenticationData(String samlArtifact, AuthenticationData authData) + throws AuthenticationException { + + try { + SAMLArtifactParser parser = new SAMLArtifactParser(samlArtifact); + // check type code 0x0001 + byte[] typeCode = parser.parseTypeCode(); + if (typeCode[0] != 0 || typeCode[1] != 1) + throw new AuthenticationException("auth.06", new Object[] { samlArtifact }); + String assertionHandle = parser.parseAssertionHandle(); + synchronized (authenticationDataStore) { + Logger.debug("Assertion stored for SAML Artifact: " + samlArtifact); + authenticationDataStore.put(assertionHandle, authData); + } + } catch (AuthenticationException ex) { + throw ex; + } catch (Throwable ex) { + throw new AuthenticationException("auth.06", new Object[] { samlArtifact }); + } + } + /** + * Creates a new session and puts it into the session store. + * + * @param id Session ID + * @return AuthenticationSession created + * @exception AuthenticationException + * thrown when an <code>AuthenticationSession</code> is running + * already for the given session ID + */ + private static AuthenticationSession newSession() throws AuthenticationException { + String sessionID = Random.nextRandom(); + AuthenticationSession newSession = new AuthenticationSession(sessionID); + synchronized (sessionStore) { + AuthenticationSession session = (AuthenticationSession) sessionStore.get(sessionID); + if (session != null) + throw new AuthenticationException("auth.01", new Object[] { sessionID }); + sessionStore.put(sessionID, newSession); + } + return newSession; + } + /** + * Retrieves a session from the session store. + * + * @param id session ID + * @return <code>AuthenticationSession</code> stored with given session ID, + * <code>null</code> if session ID unknown + */ + public static AuthenticationSession getSession(String id) throws AuthenticationException { + AuthenticationSession session = (AuthenticationSession) sessionStore.get(id); + if (session == null) + throw new AuthenticationException("auth.02", new Object[] { id }); + return session; + } + /** + * Cleans up expired session and authentication data stores. + */ + public void cleanup() { + long now = new Date().getTime(); + synchronized (sessionStore) { + Set keys = new HashSet(sessionStore.keySet()); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + String sessionID = (String) iter.next(); + AuthenticationSession session = (AuthenticationSession) sessionStore.get(sessionID); + if (now - session.getTimestampStart().getTime() > sessionTimeOut) { + Logger.info( + MOAIDMessageProvider.getInstance().getMessage( + "cleaner.02", + new Object[] { sessionID })); + sessionStore.remove(sessionID); + } + } + } + synchronized (authenticationDataStore) { + Set keys = new HashSet(authenticationDataStore.keySet()); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + String samlArtifact = (String) iter.next(); + AuthenticationData authData = + (AuthenticationData) authenticationDataStore.get(samlArtifact); + if (now - authData.getTimestamp().getTime() > authDataTimeOut) { + Logger.info( + MOAIDMessageProvider.getInstance().getMessage( + "cleaner.03", + new Object[] { samlArtifact })); + authenticationDataStore.remove(samlArtifact); + } + } + } + } + + /** + * Sets the sessionTimeOut. + * @param seconds Time out of the session in seconds + */ + public void setSecondsSessionTimeOut(long seconds) { + sessionTimeOut = 1000 * seconds; + } + /** + * Sets the authDataTimeOut. + * @param seconds Time out for signing AuthData in seconds + */ + public void setSecondsAuthDataTimeOut(long seconds) { + authDataTimeOut = 1000 * seconds; + } + + /** + * Checks a parameter. + * @param param parameter + * @return true if the parameter is null or empty + */ + private boolean isEmpty(String param) { + return param == null || param.length() == 0; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationSessionCleaner.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationSessionCleaner.java new file mode 100644 index 000000000..7e5ed6ec7 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationSessionCleaner.java @@ -0,0 +1,52 @@ +package at.gv.egovernment.moa.id.auth; + +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Thread cleaning the <code>AuthenticationServer</code> session store + * and authentication data store from garbage. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationSessionCleaner implements Runnable { + + /** interval the <code>AuthenticationSessionCleaner</code> is run in */ + private static final long SESSION_CLEANUP_INTERVAL = 30 * 60; // 30 min + + /** + * Runs the thread. Cleans the <code>AuthenticationServer</code> session store + * and authentication data store from garbage, then sleeps for given interval, and restarts. + */ + public void run() { + while (true) { + try { + Logger.debug("AuthenticationSessionCleaner run"); + AuthenticationServer.getInstance().cleanup(); + } + catch (Exception e) { + Logger.error(MOAIDMessageProvider.getInstance().getMessage("cleaner.01", null), e); + } + try { + Thread.sleep(SESSION_CLEANUP_INTERVAL * 1000); + } + catch (InterruptedException e) { + } + } + } + + /** + * start the sessionCleaner + */ + public static void start() { + // start the session cleanup thread + Thread sessionCleaner = + new Thread(new AuthenticationSessionCleaner()); + sessionCleaner.setName("SessionCleaner"); + sessionCleaner.setDaemon(true); + sessionCleaner.setPriority(Thread.MIN_PRIORITY); + sessionCleaner.start(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java new file mode 100644 index 000000000..43e88e7b5 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java @@ -0,0 +1,75 @@ +package at.gv.egovernment.moa.id.auth; + +import iaik.asn1.ObjectID; + + +/** + * Constants used throughout moa-id-auth component. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public interface MOAIDAuthConstants { + + /** servlet parameter "Target" */ + public static final String PARAM_TARGET = "Target"; + /** servlet parameter "OA" */ + public static final String PARAM_OA = "OA"; + /** servlet parameter "bkuURI" */ + public static final String PARAM_BKU = "bkuURI"; + /** servlet parameter "BKUSelectionTemplate" */ + public static final String PARAM_BKUTEMPLATE = "BKUSelectionTemplate"; + /** default BKU URL */ + public static final String DEFAULT_BKU = "http://localhost:3495/http-security-layer-request"; + /** servlet parameter "returnURI" */ + public static final String PARAM_RETURN = "returnURI"; + /** servlet parameter "Template" */ + public static final String PARAM_TEMPLATE = "Template"; + /** servlet parameter "MOASessionID" */ + public static final String PARAM_SESSIONID = "MOASessionID"; + /** servlet parameter "XMLResponse" */ + public static final String PARAM_XMLRESPONSE = "XMLResponse"; + /** servlet parameter "SAMLArtifact" */ + public static final String PARAM_SAMLARTIFACT = "SAMLArtifact"; + /** Request name {@link at.gv.egovernment.moa.id.auth.servlet.StartAuthenticationServlet} is mapped to */ + public static final String REQ_START_AUTHENTICATION = "StartAuthentication"; + /** Request name {@link at.gv.egovernment.moa.id.auth.servlet.VerifyIdentityLinkServlet} is mapped to */ + public static final String REQ_VERIFY_IDENTITY_LINK = "VerifyIdentityLink"; + /** Request name {@link at.gv.egovernment.moa.id.auth.servlet.VerifyAuthenticationBlockServlet} is mapped to */ + public static final String REQ_VERIFY_AUTH_BLOCK = "VerifyAuthBlock"; + /** Logging hierarchy used for controlling debug output of XML structures to files */ + public static final String DEBUG_OUTPUT_HIERARCHY = "moa.id.auth"; + /** Header Name for controlling the caching mechanism of the browser */ + public static final String HEADER_EXPIRES = "Expires"; + /** Header Value for controlling the caching mechanism of the browser */ + public static final String HEADER_VALUE_EXPIRES = "Sat, 6 May 1995 12:00:00 GMT"; + /** Header Name for controlling the caching mechanism of the browser */ + public static final String HEADER_PRAGMA = "Pragma"; + /** Header Value for controlling the caching mechanism of the browser */ + public static final String HEADER_VALUE_PRAGMA = "no-cache"; + /** Header Name for controlling the caching mechanism of the browser */ + public static final String HEADER_CACHE_CONTROL = "Cache-control"; + /** Header Value for controlling the caching mechanism of the browser */ + public static final String HEADER_VALUE_CACHE_CONTROL = "no-store, no-cache, must-revalidate"; + /** Header Value for controlling the caching mechanism of the browser */ + public static final String HEADER_VALUE_CACHE_CONTROL_IE = "post-check=0, pre-check=0"; + /** + * the identity link signer X509Subject names of those identity link signer certificates + * not including the identity link signer OID. The authorisation for signing the identity + * link must be checked by using their issuer names. After february 19th 2007 the OID of + * the certificate will be used fo checking the authorisation for signing identity links. + */ + public static final String[] IDENTITY_LINK_SIGNERS_WITHOUT_OID = + new String[] {"T=Dr.,CN=Nikolaus Schwab,O=BM f. Inneres i.A. des gf. Mitgieds der Datenschutzkommission", + "T=Dr.,CN=Nikolaus Schwab,O=BM f. Inneres i.A. des gf. Mitglieds der Datenschutzkommission"}; + /** + * the number of the certifcate extension "Eigenschaft zur Ausstellung von Personenbindungen" + */ + public static final String IDENTITY_LINK_SIGNER_OID_NUMBER = "1.2.40.0.10.1.7.1"; + /** + * the OID of the identity link signer certificate (Eigenschaft zur Ausstellung von Personenbindungen); + * used for checking the authorisation for signing the identity link for identity links signed after february 19th 2007 + */ + public static final ObjectID IDENTITY_LINK_SIGNER_OID = new ObjectID(IDENTITY_LINK_SIGNER_OID_NUMBER); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java new file mode 100644 index 000000000..7964e2fb6 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java @@ -0,0 +1,163 @@ +package at.gv.egovernment.moa.id.auth; + +import iaik.pki.PKIException; +import iaik.pki.jsse.IAIKX509TrustManager; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Properties; + +import javax.activation.CommandMap; +import javax.activation.MailcapCommandMap; +import javax.mail.Session; +import javax.net.ssl.SSLSocketFactory; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.iaik.config.LoggerConfigImpl; +import at.gv.egovernment.moa.id.util.AxisSecureSocketFactory; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.logging.LoggingContext; +import at.gv.egovernment.moa.logging.LoggingContextManager; +import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider; +import at.gv.egovernment.moa.spss.server.iaik.config.IaikConfigurator; +import at.gv.egovernment.moa.util.Constants; + +/** + * Web application initializer + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class MOAIDAuthInitializer { + + /** a boolean identifying if the MOAIDAuthInitializer has been startet */ + public static boolean initialized = false; + + /** + * Initializes the web application components which need initialization: + * logging, JSSE, MOA-ID Auth configuration, Axis, session cleaner. + */ + public static void initialize() throws ConfigurationException, + PKIException, IOException, GeneralSecurityException { + if (initialized) return; + initialized = true; + Logger.setHierarchy("moa.id.auth"); + Logger.info("Default java file.encoding: " + + System.getProperty("file.encoding")); + + //JDK bug workaround according to: + // http://jce.iaik.tugraz.at/products/03_cms/faq/index.php#JarVerifier + // register content data handlers for S/MIME types + MailcapCommandMap mc = new MailcapCommandMap(); + CommandMap.setDefaultCommandMap(mc); + + // create some properties and get the default Session + Properties props = new Properties(); + props.put("mail.smtp.host", "localhost"); + Session session = Session.getDefaultInstance(props, null); + + // Restricts TLS cipher suites + System.setProperty( + "https.cipherSuites", + "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5,SSL_RSA_WITH_3DES_EDE_CBC_SHA"); + // load some jsse classes so that the integrity of the jars can be + // verified + // before the iaik jce is installed as the security provider + // this workaround is only needed when sun jsse is used in conjunction + // with + // iaik-jce (on jdk1.3) + ClassLoader cl = MOAIDAuthInitializer.class.getClassLoader(); + try { + cl.loadClass("javax.security.cert.Certificate"); // from jcert.jar + } catch (ClassNotFoundException e) { + Logger.warn(MOAIDMessageProvider.getInstance().getMessage( + "init.01", null), e); + } + + // Initializes SSLSocketFactory store + SSLUtils.initialize(); + + // Initializes Namespace Map + Constants.nSMap.put(Constants.SAML_PREFIX, Constants.SAML_NS_URI); + Constants.nSMap.put(Constants.ECDSA_PREFIX, + "http://www.w3.org/2001/04/xmldsig-more#"); + Constants.nSMap.put(Constants.DSIG_PREFIX, Constants.DSIG_NS_URI); + + // Loads the configuration + AuthConfigurationProvider authConf = AuthConfigurationProvider.reload(); + ConnectionParameter moaSPConnParam = authConf + .getMoaSpConnectionParameter(); + + // If MOA-SP API calls: loads MOA-SP configuration and configures IAIK + if (moaSPConnParam == null) { + try { + LoggingContextManager.getInstance().setLoggingContext( + new LoggingContext("startup")); + ConfigurationProvider config = ConfigurationProvider + .getInstance(); + new IaikConfigurator().configure(config); + } catch (at.gv.egovernment.moa.spss.server.config.ConfigurationException ex) { + throw new ConfigurationException("config.10", new Object[] { ex + .toString() }, ex); + } + } + + // Initializes IAIKX509TrustManager logging + String log4jConfigURL = System.getProperty("log4j.configuration"); + if (log4jConfigURL != null) { + IAIKX509TrustManager.initLog(new LoggerConfigImpl(log4jConfigURL)); + } + + // Initializes the Axis secure socket factory for use in calling the + // MOA-SP web service + if (moaSPConnParam != null && moaSPConnParam.isHTTPSURL()) { + SSLSocketFactory ssf = SSLUtils.getSSLSocketFactory(authConf, + moaSPConnParam); + AxisSecureSocketFactory.initialize(ssf); + } + + // sets the authentication session and authentication data time outs + String param = authConf + .getGenericConfigurationParameter(AuthConfigurationProvider.AUTH_SESSION_TIMEOUT_PROPERTY); + if (param != null) { + long sessionTimeOut = 0; + try { + sessionTimeOut = new Long(param).longValue(); + } catch (NumberFormatException ex) { + Logger + .error(MOAIDMessageProvider + .getInstance() + .getMessage( + "config.05", + new Object[] { AuthConfigurationProvider.AUTH_SESSION_TIMEOUT_PROPERTY })); + } + if (sessionTimeOut > 0) + AuthenticationServer.getInstance() + .setSecondsSessionTimeOut(sessionTimeOut); + } + param = authConf + .getGenericConfigurationParameter(AuthConfigurationProvider.AUTH_DATA_TIMEOUT_PROPERTY); + if (param != null) { + long authDataTimeOut = 0; + try { + authDataTimeOut = new Long(param).longValue(); + } catch (NumberFormatException ex) { + Logger + .error(MOAIDMessageProvider + .getInstance() + .getMessage( + "config.05", + new Object[] { AuthConfigurationProvider.AUTH_DATA_TIMEOUT_PROPERTY })); + } + if (authDataTimeOut > 0) + AuthenticationServer.getInstance() + .setSecondsAuthDataTimeOut(authDataTimeOut); + } + + } + +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/WrongParametersException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/WrongParametersException.java new file mode 100644 index 000000000..3ce2798ea --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/WrongParametersException.java @@ -0,0 +1,21 @@ +package at.gv.egovernment.moa.id.auth; + +import at.gv.egovernment.moa.id.MOAIDException; + +/** + * Exception thrown when the <code>AuthenticationServer</code> API is + * called with wrong parameters provided. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class WrongParametersException extends MOAIDException { + + /** + * Constructor + */ + public WrongParametersException(String call, String parameter) { + super("auth.05", new Object[] {call, parameter}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationAssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationAssertionBuilder.java new file mode 100644 index 000000000..241cf0afc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationAssertionBuilder.java @@ -0,0 +1,88 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.List; + +import javax.xml.transform.TransformerException; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Base class for building authentication the AUTHBlock and final OA data SAML assertions. + * Encapsulates methods used by the two specific builders + * {@link at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder AuthenticationBlockAssertionBuilder} + * and + * {@link at.gv.egovernment.moa.id.auth.builder.AuthenticationDataAssertionBuilder AuthenticationDataAssertionBuilder} + * + * @author Harald Bratko + */ +public class AuthenticationAssertionBuilder { + + /** the NewLine representation in Java*/ + protected static String NL = "\n"; + + protected static String SAML_ATTRIBUTE = + " <saml:Attribute AttributeName=''{0}'' AttributeNamespace=''{1}''>" + NL + + " <saml:AttributeValue>{2}</saml:AttributeValue>" + NL + + " </saml:Attribute>"+ NL; + + /** + * Empty constructor + */ + public AuthenticationAssertionBuilder() { + } + + /** + * Builds the SAML attributes to be appended to the AUTHBlock or to the SAML assertion + * delivered to the online application. + * The method traverses through the list of given SAML attribute objects and builds an + * XML structure (String representation) for each of the attributes. + * + * @param extendedSAMLAttributes The SAML attributes to be appended to the AUTHBlock or + * to the SAML assertion delivered to the online application. + * @return A string representation including the XML structures of + * the SAML attributes. + * + * @throws ParseException If an error occurs on serializing an SAML attribute. + */ + protected String buildExtendedSAMLAttributes(List extendedSAMLAttributes) throws ParseException + { + StringBuffer sb = new StringBuffer(); + if (extendedSAMLAttributes!=null) { + Iterator it = extendedSAMLAttributes.iterator(); + while (it.hasNext()) { + ExtendedSAMLAttribute extendedSAMLAttribute = (ExtendedSAMLAttribute)it.next(); + Object value = extendedSAMLAttribute.getValue(); + String name = extendedSAMLAttribute.getName(); + String namespace = extendedSAMLAttribute.getNameSpace(); + if (value instanceof String) { + sb.append(MessageFormat.format( SAML_ATTRIBUTE, new Object[] {name, namespace, value})); + } else if (value instanceof Element) { + try { + String serializedValue = DOMUtils.serializeNode((Element)(value)); + serializedValue = StringUtils.removeXMLDeclaration(serializedValue); + sb.append(MessageFormat.format( SAML_ATTRIBUTE, new Object[] {name, namespace, serializedValue})); + } catch (TransformerException e) { + Logger.error("Error on serializing SAML attribute \"" + name + + " (namespace: \"" + namespace + "\"."); + throw new ParseException("parser.05", new Object[] { name, namespace}); + } catch (IOException e) { + Logger.error("Error on serializing SAML attribute \"" + name + + " (namespace: \"" + namespace + "\"."); + throw new ParseException("parser.05", new Object[] { name, namespace}); + } + } + } + } + return sb.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationBlockAssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationBlockAssertionBuilder.java new file mode 100644 index 000000000..60cd11ed6 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationBlockAssertionBuilder.java @@ -0,0 +1,146 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.text.MessageFormat; +import java.util.List; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; + +/** + * Builder for the authentication block <code><saml:Assertion></code> + * to be included in a <code><CreateXMLSignatureResponse></code>. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationBlockAssertionBuilder extends AuthenticationAssertionBuilder implements Constants { + + /** template for the Auth-Block */ + private static String AUTH_BLOCK = + "<saml:Assertion xmlns:saml=''" + SAML_NS_URI + "''{0} MajorVersion=''1'' MinorVersion=''0'' AssertionID=''any'' Issuer=''{1}'' IssueInstant=''{2}''>" + NL + + " <saml:AttributeStatement>" + NL + + " <saml:Subject>" + NL + + " <saml:NameIdentifier>{3}</saml:NameIdentifier>" + NL + + " </saml:Subject>" + NL + + "{4}" + + " <saml:Attribute AttributeName=''OA'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{5}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL + + " <saml:Attribute AttributeName=''Geburtsdatum'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{6}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL + + "{7}" + + " </saml:AttributeStatement>" + NL + + "</saml:Assertion>"; + + private static String GESCHAEFTS_BEREICH_ATTRIBUTE = + " <saml:Attribute AttributeName=''Geschaeftsbereich'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{0}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL; + + private static String WBPK_ATTRIBUTE = + " <saml:Attribute AttributeName=''wbPK'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>" + NL + + " <pr:Identification>" + NL + + " <pr:Value>{0}</pr:Value>" + NL + + " <pr:Type>{1}</pr:Type>" + NL + + " </pr:Identification>" + NL + + " </saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL; + + /** + * The number of SAML attributes included in this AUTH-Block (without the extended SAML attributes). + */ + public static final int NUM_OF_SAML_ATTRIBUTES = 3; + + /** + * Constructor for AuthenticationBlockAssertionBuilder. + */ + public AuthenticationBlockAssertionBuilder() { + super(); + } + + /** + * Builds the authentication block <code><saml:Assertion></code> + * + * @param issuer authentication block issuer; <code>"GivenName FamilyName"</code> + * @param issueInstant current timestamp + * @param authURL URL of MOA-ID authentication component + * @param target "Geschäftsbereich"; maybe <code>null</code> if the application + * is a business application + * @param identityLinkValue the content of the <code><pr:Value></code> + * child element of the <code><pr:Identification></code> + * element derived from the Identitylink; this is the + * value of the <code>wbPK</code>; + * maybe <code>null</code> if the application is a public service + * @param identityLinkType the content of the <code><pr:Type></code> + * child element of the <code><pr:Identification></code> + * element derived from the Identitylink; this includes the + * URN prefix and the identification number of the business + * application used as input for wbPK computation; + * maybe <code>null</code> if the application is a public service + * @param oaURL public URL of online application requested + * @param gebDat The date of birth from the identity link. + * @param extendedSAMLAttributes The SAML attributes to be appended to the AUTHBlock. + * + * @return String representation of authentication block + * <code><saml:Assertion></code> built + * + * @throws BuildException If an error occurs on serializing an extended SAML attribute + * to be appended to the AUTH-Block. + */ + public String buildAuthBlock( + String issuer, + String issueInstant, + String authURL, + String target, + String identityLinkValue, + String identityLinkType, + String oaURL, + String gebDat, + List extendedSAMLAttributes, + AuthenticationSession session) + throws BuildException + { + session.setSAMLAttributeGebeORwbpk(true); + String gebeORwbpk = ""; + String wbpkNSDeclaration = ""; + if (target == null) { + // OA is a business application + if (!Constants.URN_PREFIX_HPI.equals(identityLinkType)) { + // Only add wbPKs to AUTH-Block. HPIs can be added to the AUTH-Block by the corresponding Validator + gebeORwbpk = MessageFormat.format(WBPK_ATTRIBUTE, new Object[] { identityLinkValue, identityLinkType }); + wbpkNSDeclaration = " xmlns:pr=\"" + PD_NS_URI + "\""; + } else { + // We do not have a wbPK, therefore no SAML-Attribute is provided + session.setSAMLAttributeGebeORwbpk(false); + } + } else { + gebeORwbpk = MessageFormat.format(GESCHAEFTS_BEREICH_ATTRIBUTE, new Object[] { target }); + } + + String assertion; + try { + assertion = MessageFormat.format( + AUTH_BLOCK, new Object[] { + wbpkNSDeclaration, + issuer, + issueInstant, + authURL, + gebeORwbpk, + oaURL, + gebDat, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } catch (ParseException e) { + Logger.error("Error on building AUTH-Block: " + e.getMessage()); + throw new BuildException("builder.00", new Object[] { "AUTH-Block", e.toString()}); + } + + return assertion; + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java new file mode 100644 index 000000000..53520c846 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java @@ -0,0 +1,156 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.text.MessageFormat; +import java.util.List; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Builder for the authentication data <code><saml:Assertion></code> + * to be provided by the MOA ID Auth component. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationDataAssertionBuilder extends AuthenticationAssertionBuilder implements Constants { + /** private static String NL contains the NewLine representation in Java*/ + private static final String NL = "\n"; + /** + * XML template for the <code><saml:Assertion></code> to be built + */ + private static final String AUTH_DATA = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + NL + + "<saml:Assertion xmlns:saml=''" + SAML_NS_URI + "'' xmlns:pr=''" + PD_NS_URI + "'' xmlns:xsi=''" + XSI_NS_URI + "''" + + " xmlns:si=''" + XSI_NS_URI + "''" + + " MajorVersion=''1'' MinorVersion=''0'' AssertionID=''{0}'' Issuer=''{1}'' IssueInstant=''{2}''>" + NL + + " <saml:AttributeStatement>" + NL + + " <saml:Subject>" + NL + + " <saml:NameIdentifier NameQualifier=''{3}''>{4}</saml:NameIdentifier>" + NL + + " <saml:SubjectConfirmation>" + NL + + " <saml:ConfirmationMethod>" + MOA_NS_URI + "cm</saml:ConfirmationMethod>" + NL + + " <saml:SubjectConfirmationData>{5}{6}</saml:SubjectConfirmationData>" + NL + + " </saml:SubjectConfirmation>" + NL + + " </saml:Subject>" + NL + + " <saml:Attribute AttributeName=''PersonData'' AttributeNamespace=''" + PD_NS_URI + "''>" + NL + + " <saml:AttributeValue>{7}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL + + " <saml:Attribute AttributeName=''isQualifiedCertificate'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{8}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL + + " <saml:Attribute AttributeName=''bkuURL'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{9}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL + + "{10}" + + "{11}" + + "{12}" + + " </saml:AttributeStatement>" + NL + + "</saml:Assertion>"; + /** + * XML template for the <code><saml:Attribute></code> named <code>"isPublicAuthority"</code>, + * to be inserted into the <code><saml:Assertion></code> + */ + private static final String PUBLIC_AUTHORITY_ATT = + " <saml:Attribute AttributeName=''isPublicAuthority'' AttributeNamespace=''urn:oid:1.2.40.0.10.1.1.1''>" + NL + + " <saml:AttributeValue>{0}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL; + + private static final String SIGNER_CERTIFICATE_ATT = + " <saml:Attribute AttributeName=''SignerCertificate'' AttributeNamespace=''" + MOA_NS_URI + "''>" + NL + + " <saml:AttributeValue>{0}</saml:AttributeValue>" + NL + + " </saml:Attribute>" + NL; + + /** + * Constructor for AuthenticationDataAssertionBuilder. + */ + public AuthenticationDataAssertionBuilder() { + super(); + } + + /** + * Builds the authentication data <code><saml:Assertion></code>. + * + * @param authData the <code>AuthenticationData</code> to build the + * <code><saml:Assertion></code> from + * @param xmlPersonData <code>lt;pr:Person></code> element as a String + * @param xmlAuthBlock authentication block to be included in a + * <code>lt;saml:SubjectConfirmationData></code> element; may include + * the <code>"Stammzahl"</code> or not; may be empty + * @param xmlIdentityLink the IdentityLink + * @param signerCertificateBase64 Base64 encoded certificate of the signer. Maybe + * an empty string if the signer certificate should not be provided. + * Will be ignored if the <code>businessService</code> parameter is + * set to <code>false</code>. + * @param businessService <code>true</code> if the online application is a + * business service, otherwise <code>false</code> + * @return the <code><saml:Assertion></code> + * @throws BuildException if an error occurs during the build process + */ + public String build( + AuthenticationData authData, + String xmlPersonData, + String xmlAuthBlock, + String xmlIdentityLink, + String bkuURL, + String signerCertificateBase64, + boolean businessService, + List extendedSAMLAttributes) + throws BuildException + { + + String isQualifiedCertificate = authData.isQualifiedCertificate() ? "true" : "false"; + String publicAuthorityAttribute = ""; + if (authData.isPublicAuthority()) { + String publicAuthorityIdentification = authData.getPublicAuthorityCode(); + if (publicAuthorityIdentification == null) + publicAuthorityIdentification = "True"; + publicAuthorityAttribute = MessageFormat.format( + PUBLIC_AUTHORITY_ATT, new Object[] { publicAuthorityIdentification }); + } + + + String signerCertificateAttribute = ""; + if (signerCertificateBase64 != "") { + signerCertificateAttribute = MessageFormat.format( + SIGNER_CERTIFICATE_ATT, new Object[] { signerCertificateBase64 }); + } + + String pkType; + String pkValue; + if (businessService) { + pkType = authData.getIdentificationType(); + pkValue = authData.getWBPK(); + + } else { + pkType = URN_PREFIX_BPK; + pkValue = authData.getBPK(); + } + + String assertion; + try { + assertion = MessageFormat.format(AUTH_DATA, new Object[] { + authData.getAssertionID(), + authData.getIssuer(), + authData.getIssueInstant(), + pkType, + pkValue, + StringUtils.removeXMLDeclaration(xmlAuthBlock), + StringUtils.removeXMLDeclaration(xmlIdentityLink), + StringUtils.removeXMLDeclaration(xmlPersonData), + isQualifiedCertificate, + bkuURL, + publicAuthorityAttribute, + signerCertificateAttribute, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } catch (ParseException e) { + Logger.error("Error on building Authentication Data Assertion: " + e.getMessage()); + throw new BuildException("builder.00", new Object[] { "Authentication Data Assertion", e.toString()}); + } + return assertion; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java new file mode 100644 index 000000000..6cc8c1be8 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java @@ -0,0 +1,49 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.security.MessageDigest; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.Constants; + +/** + * Builder for the bPK, as defined in + * <code>"Ableitung f¨r die bereichsspezifische Personenkennzeichnung"</code> + * version <code>1.0.1</code> from <code>"reference.e-government.gv.at"</code>. + * + * @author Paul Schamberger + * @version $Id$ + */ +public class BPKBuilder { + + /** + * Builds the bPK from the given parameters. + * @param identificationValue Base64 encoded "Stammzahl" + * @param target "Bereich lt. Verordnung des BKA" + * @return bPK in a BASE64 encoding + * @throws BuildException if an error occurs on building the bPK + */ + public String buildBPK(String identificationValue, String target) + throws BuildException { + + if ((identificationValue == null || + identificationValue.length() == 0 || + target == null || + target.length() == 0)) + { + throw new BuildException("builder.00", + new Object[] {"BPK", "Unvollständige Parameterangaben: identificationValue=" + + identificationValue + ",target=" + target}); + } + String basisbegriff = identificationValue + "+" + Constants.URN_PREFIX_CDID + "+" + target; + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] hash = md.digest(basisbegriff.getBytes("ISO-8859-1")); + String hashBase64 = Base64Utils.encode(hash); + return hashBase64; + } catch (Exception ex) { + throw new BuildException("builder.00", new Object[] {"BPK", ex.toString()}, ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/Builder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/Builder.java new file mode 100644 index 000000000..3a2ee07de --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/Builder.java @@ -0,0 +1,59 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Base class for HTML/XML builders providing commonly useful functions. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class Builder { + + /** + * Replaces a given number of occurences of a special tag in an XML or HTML template by a value. + * @param template html template + * @param tag special tag + * @param value value replacing the tag + * @param expected specifies if the tag is expected to present; if <code>true</code> and the tag + * is not present, an exception is thrown; if <code>false</code> and the tag is + * not present, the original string is returned + * @param maxreplacements Set -1 to replace each occurence of tag, or limit replacements by a given positive number + * @return XML or HTML code, the tag replaced + * @throws BuildException when template does not contain the tag + */ + protected String replaceTag( + String template, + String tag, + String value, + boolean expected, + int maxreplacements) + throws BuildException + { + String result = template; + int index = result.indexOf(tag); + if (index < 0) { + if (expected) { + // Substring not found but should + throw new BuildException( + "builder.01", + new Object[] {"<" + tag.substring(1, tag.length() - 1) + ">"}); + } + } else { + // replace each occurence + if (maxreplacements == -1) { + return StringUtils.replaceAll(template, tag, value); + } else { + int found = 1; + while (index > -1 && (found <= maxreplacements)) { + result = result.substring(0, index) + value + result.substring(index + tag.length()); + index = result.indexOf(tag); + if (index > -1) found += 1; + } + } + } + return result; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CertInfoVerifyXMLSignatureRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CertInfoVerifyXMLSignatureRequestBuilder.java new file mode 100644 index 000000000..06c81f49e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CertInfoVerifyXMLSignatureRequestBuilder.java @@ -0,0 +1,84 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.io.IOException; +import java.text.MessageFormat; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.FileUtils; + +/** + * Builder for the <code><VerifyXMLSignatureRequest></code> structure + * used for presenting certificate information in the secure viewer of the security layer implementation. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class CertInfoVerifyXMLSignatureRequestBuilder extends Builder implements Constants { + + /** special tag in the VerifyXMLRequest template to be substituted for a <code><dsig:Signature></code> */ + private static final String SIGNATURE_TAG = "<dsig:Signature/>"; + + /** private static String nl contains the NewLine representation in Java*/ + private static final String nl = "\n"; + + /** + * XML template for the CertInfoVerifyXMLSignatureRequest to be built + */ + static final String CERTINFO_REQUEST = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + nl + + "<{0}:VerifyXMLSignatureRequest {2} xmlns:dsig=\"" + DSIG_NS_URI + "\">" + nl + + " <{0}:SignatureInfo>" + nl + + " <{0}:SignatureEnvironment>" + nl + + " <{1}:XMLContent xml:space=\"preserve\"><dsig:Signature/></{1}:XMLContent>" + nl + + " </{0}:SignatureEnvironment>" + nl + + " <{0}:SignatureLocation>//dsig:Signature</{0}:SignatureLocation>" + nl + + " </{0}:SignatureInfo>" + nl + + "</{0}:VerifyXMLSignatureRequest>"; + + /** + * Constructor + */ + public CertInfoVerifyXMLSignatureRequestBuilder() { + super(); + } + /** + * Builds the <code><VerifyXMLSignatureRequest></code> structure. + * @return the XML structure + * @throws BuildException + */ + public String build(boolean slVersion12) throws BuildException { + + String sl10Prefix; + String sl11Prefix; + String slNsDeclaration; + + if (slVersion12) { + + sl10Prefix = SL12_PREFIX; + sl11Prefix = SL12_PREFIX; + slNsDeclaration = "xmlns:" + SL12_PREFIX + "=\"" + SL12_NS_URI + "\""; + + } else { + + sl10Prefix = SL10_PREFIX; + sl11Prefix = SL11_PREFIX; + slNsDeclaration = "xmlns:" + sl11Prefix + "=\"" + SL11_NS_URI + "\" xmlns:" + sl10Prefix + "=\"" + SL10_NS_URI + "\""; + + } + + String certInfoRequest = MessageFormat.format(CERTINFO_REQUEST, new Object[] {sl11Prefix, sl10Prefix, slNsDeclaration}); + String resDsigSignature = "resources/xmldata/CertInfoDsigSignature.xml"; + + + try { + String dsigSignature = FileUtils.readResource(resDsigSignature, "UTF-8"); + certInfoRequest = replaceTag(certInfoRequest, SIGNATURE_TAG, dsigSignature, true, 1); + return certInfoRequest; + } + catch (IOException ex) { + throw new BuildException("auth.04", new Object[] {resDsigSignature, ex.toString()}); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java new file mode 100644 index 000000000..e9a9f308d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java @@ -0,0 +1,93 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.text.MessageFormat; + +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Builder for the <code><CreateXMLSignatureRequest></code> structure + * used for requesting a signature under the authentication block from the + * security layer implementation. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class CreateXMLSignatureRequestBuilder implements Constants { + /** private static String nl contains the NewLine representation in Java*/ + private static final String nl = "\n"; + /** + * XML template for the <code><moa:CreateXMLSignatureRequest></code> to be built + */ + private static final String CREATE_XML_SIGNATURE_REQUEST = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + nl + + "<{3}:CreateXMLSignatureRequest xmlns:dsig=''" + DSIG_NS_URI + "'' {5}>" + nl + + " <{3}:KeyboxIdentifier>{1}</{3}:KeyboxIdentifier>" + nl + + " <{3}:DataObjectInfo Structure=''detached''>" + nl + + " <{4}:DataObject Reference=''''/>" + nl + + "{2}" + + " </{3}:DataObjectInfo>" + nl + + " <{3}:SignatureInfo>" + nl + + " <{3}:SignatureEnvironment>" + nl + + " <{4}:XMLContent>{0}</{4}:XMLContent>" + nl + + " </{3}:SignatureEnvironment>" + nl + + " <{3}:SignatureLocation Index=''2''>/saml:Assertion</{3}:SignatureLocation>" + nl + + " </{3}:SignatureInfo>" + nl + + "</{3}:CreateXMLSignatureRequest>"; + + + /** + * Constructor for CreateXMLSignatureRequestBuilder. + */ + public CreateXMLSignatureRequestBuilder() { + super(); + } + + /** + * Builds the <code><CreateXMLSignatureRequest></code>. + * + * @param authBlock String representation of XML authentication block + * @param keyBoxIdentifier the key box identifier which will be used (e.g. CertifiedKeypair) + * @param slVersion12 specifies whether the Security Layer version number is 1.2 or not + * @return String representation of <code><CreateXMLSignatureRequest></code> + */ + public String build(String authBlock, String keyBoxIdentifier, String[] dsigTransformInfos, boolean slVersion12) { + + String sl10Prefix; + String sl11Prefix; + String slNsDeclaration; + + String dsigTransformInfosString = ""; + for (int i = 0; i < dsigTransformInfos.length; i++) { + dsigTransformInfosString += dsigTransformInfos[i]; + } + + if (slVersion12) { + + // replace the SecurityLayer namespace prefixes and URIs within the transforms + dsigTransformInfosString = StringUtils.changeSLVersion(dsigTransformInfosString, + SL10_PREFIX, SL12_PREFIX, + SL10_NS_URI, SL12_NS_URI); + sl10Prefix = SL12_PREFIX; + sl11Prefix = SL12_PREFIX; + slNsDeclaration = "xmlns:" + SL12_PREFIX + "='" + SL12_NS_URI + "'"; + + } else { + + sl10Prefix = SL10_PREFIX; + sl11Prefix = SL11_PREFIX; + slNsDeclaration = "xmlns:" + sl10Prefix + "='" + SL10_NS_URI + "' xmlns:" + sl11Prefix + "='" + SL11_NS_URI + "'"; + + } + + String request = MessageFormat.format( + CREATE_XML_SIGNATURE_REQUEST, new Object[] { authBlock, + keyBoxIdentifier, + dsigTransformInfosString, + sl11Prefix, + sl10Prefix, + slNsDeclaration }); + + return request; + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/DataURLBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/DataURLBuilder.java new file mode 100644 index 000000000..30cc1df5a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/DataURLBuilder.java @@ -0,0 +1,83 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Builds a DataURL parameter meant for the security layer implementation + * to respond to. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class DataURLBuilder { + + /** + * Constructor for DataURLBuilder. + */ + public DataURLBuilder() { + super(); + } + + /** + * Constructs a data URL for <code>VerifyIdentityLink</code> or <code>VerifyAuthenticationBlock</code>, + * including the <code>MOASessionID</code> as a parameter. + * + * @param authBaseURL base URL (context path) of the MOA ID Authentication component, + * including a trailing <code>'/'</code> + * @param authServletName request part of the data URL + * @param sessionID sessionID to be included in the dataURL + * @return String + */ + public String buildDataURL(String authBaseURL, String authServletName, String sessionID) { + + String individualDataURLPrefix = null; + String dataURL; + try { + //check if an individual prefix is configured + individualDataURLPrefix = AuthConfigurationProvider.getInstance(). + getGenericConfigurationParameter(AuthConfigurationProvider.INDIVIDUAL_DATA_URL_PREFIX); + + if (null != individualDataURLPrefix) { + + //check individualDataURLPrefix + if(!individualDataURLPrefix.startsWith("http")) + throw(new ConfigurationException("config.13", new Object[] { individualDataURLPrefix})); + + //when ok then use it + dataURL = individualDataURLPrefix + authServletName; + } else + dataURL = authBaseURL + authServletName; + + } catch (ConfigurationException e) { + Logger.warn(e); + Logger.warn(MOAIDMessageProvider.getInstance().getMessage("config.12", new Object[] { authBaseURL } )); + dataURL = authBaseURL + authServletName; + } + + dataURL = addParameter(dataURL, AuthServlet.PARAM_SESSIONID, sessionID); + return dataURL; + } + + /** + * Method addParameter. + * @param urlString represents the url + * @param paramname is the parameter to be added + * @param value is the value of that parameter + * @return String + */ + private String addParameter(String urlString, String paramname, String value) { + String url = urlString; + if (paramname != null) { + if (url.indexOf("?") < 0) + url += "?"; + else + url += "&"; + url += paramname + "=" + value; + } + return url; + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/GetIdentityLinkFormBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/GetIdentityLinkFormBuilder.java new file mode 100644 index 000000000..0d0595b69 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/GetIdentityLinkFormBuilder.java @@ -0,0 +1,150 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import at.gv.egovernment.moa.id.BuildException; + +/** + * Builder for HTML form requesting the security layer implementation + * to get the identity link from smartcard by a <code><InfoboxReadRequest></code>. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class GetIdentityLinkFormBuilder extends Builder { + /** private static String NL contains the NewLine representation in Java*/ + private static final String nl = "\n"; + /** special tag in the HTML template to be substituted for the BKU URL */ + private static final String BKU_TAG = "<BKU>"; + /** special tag in the HTML template to be substituted for the XML request */ + private static final String XMLREQUEST_TAG = "<XMLRequest>"; + /** special tag in the HTML template to be substituted for the data URL */ + private static final String DATAURL_TAG = "<DataURL>"; + /** special tag in the HTML template to be substituted for certificate info XML request */ + private static final String CERTINFO_XMLREQUEST_TAG = "<CertInfoXMLRequest>"; + /** special tag in the HTML template to be substituted for the certificate info data URL */ + private static final String CERTINFO_DATAURL_TAG = "<CertInfoDataURL>"; + /** special tag in the HTML template to be substituted for the infoboxes to be pushed from the BKU */ + private static final String PUSHINFOBOX_TAG = "<PushInfobox>"; + /** private static int all contains the representation to replace all tags*/ + private static final int ALL = -1; + + /** default HTML template */ + private static final String DEFAULT_HTML_TEMPLATE = + "<html>" + nl + + "<head>" + nl + + "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">" + nl + + "<title>Anmeldung mit Bürgerkarte</title>" + nl + + "</head>" + nl + + "<body>" + nl + + "<form name=\"GetIdentityLinkForm\"" + nl + + " action=\"" + BKU_TAG + "\"" + nl + + " method=\"post\">" + nl + + " <input type=\"hidden\" " + nl + + " name=\"XMLRequest\"" + nl + + " value=\"" + XMLREQUEST_TAG + "\"/>" + nl + + " <input type=\"hidden\" " + nl + + " name=\"DataURL\"" + nl + + " value=\"" + DATAURL_TAG + "\"/>" + nl + + " <input type=\"hidden\" " + nl + + " name=\"PushInfobox\"" + nl + + " value=\"" + PUSHINFOBOX_TAG + "\"/>" + nl + + " <input type=\"submit\" value=\"Anmeldung mit Bürgerkarte\"/>" + nl + + "</form>" + nl + + "<form name=\"CertificateInfoForm\"" + nl + + " action=\"" + BKU_TAG + "\"" + nl + + " method=\"post\">" + nl + + " <input type=\"hidden\" " + nl + + " name=\"XMLRequest\"" + nl + + " value=\"" + CERTINFO_XMLREQUEST_TAG + "\"/>" + nl + + " <input type=\"hidden\" " + nl + + " name=\"DataURL\"" + nl + + " value=\"" + CERTINFO_DATAURL_TAG + "\"/>" + nl + +// " <input type=\"submit\" value=\"Information zu Wurzelzertifikaten\"/>" + nl + + " <input type=\"hidden\" value=\"Information zu Wurzelzertifikaten\"/>" + nl + + "</form>" + nl + + "</body>" + nl + + "</html>"; + + /** + * Constructor for GetIdentityLinkFormBuilder. + */ + public GetIdentityLinkFormBuilder() { + super(); + } + /** + * Builds the HTML form, including XML Request and data URL as parameters. + * + * @param htmlTemplate template to be used for the HTML form; + * may be <code>null</code>, in this case a default layout will be produced + * @param xmlRequest XML Request to be sent as a parameter in the form + * @param bkuURL URL of the "Bürgerkartenumgebung" the form will be submitted to; + * may be <code>null</code>, in this case the default URL will be used + * @param dataURL DataURL to be sent as a parameter in the form + */ + public String build( + String htmlTemplate, + String bkuURL, + String xmlRequest, + String dataURL, + String certInfoXMLRequest, + String certInfoDataURL, + String pushInfobox) + throws BuildException + { + String htmlForm = htmlTemplate == null ? DEFAULT_HTML_TEMPLATE : htmlTemplate; +// String bku = bkuURL == null ? DEFAULT_BKU : bkuURL; + htmlForm = replaceTag(htmlForm, BKU_TAG, bkuURL, true, ALL); + htmlForm = replaceTag(htmlForm, XMLREQUEST_TAG, encodeParameter(xmlRequest), true, ALL); + htmlForm = replaceTag(htmlForm, DATAURL_TAG, dataURL, true, ALL); + htmlForm = replaceTag(htmlForm, PUSHINFOBOX_TAG, pushInfobox, false, ALL); +//new:wird oben mitreplaced htmlForm = replaceTag(htmlForm, BKU_TAG, bkuURL); + htmlForm = replaceTag(htmlForm, CERTINFO_XMLREQUEST_TAG, encodeParameter(certInfoXMLRequest), true, ALL); + htmlForm = replaceTag(htmlForm, CERTINFO_DATAURL_TAG, certInfoDataURL, true, ALL); + return htmlForm; + } + /** + * Encodes a string for inclusion as a parameter in the form. + * Double quotes are substituted by <code>"&quot;"</code>. + * @param s the string to be encoded + * @return the string encoded + * @throws BuildException on any exception encountered + */ + public static String encodeParameter(String s) throws BuildException { + StringReader in = new StringReader(s); + StringWriter out = new StringWriter(); + try { + for (int ch = in.read(); ch >= 0; ch = in.read()) { + if (ch == '"') + out.write("""); + else if (ch == '<') + out.write("<"); + else if (ch == '>') + out.write(">"); + else if (ch == 'ä') + out.write("ä"); + else if (ch == 'ö') + out.write("ö"); + else if (ch == 'ü') + out.write("ü"); + else if (ch == 'Ä') + out.write("Ä"); + else if (ch == 'Ö') + out.write("Ö"); + else if (ch == 'Ü') + out.write("Ü"); + else if (ch == 'ß') + out.write("ß"); + else + out.write(ch); + } + } + catch (IOException ex) { + throw new BuildException("builder.00", new Object[] {"GetIdentityLinkForm", ex.toString()}); + } + return out.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxReadRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxReadRequestBuilder.java new file mode 100644 index 000000000..c2bafe43b --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxReadRequestBuilder.java @@ -0,0 +1,86 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import at.gv.egovernment.moa.util.Constants; + +/** + * Builder for the <code><InfoboxReadRequest></code> structure + * used for requesting the identity link from the security layer implementation. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class InfoboxReadRequestBuilder implements Constants { + + + /** + * Constructor for InfoboxReadRequestBuilder. + */ + public InfoboxReadRequestBuilder() { + } + + + /** + * Builds an <code><InfoboxReadRequest></code>. + * + * @param slVersion12 specifies whether the Security Layer version is + * version 1.2 or not + * @param businessService specifies whether the online application is a + * business service or not + * @param identityLinkDomainIdentifier the identification number of the business + * company; maybe <code>null</code> if the OA + * is a public service; must not be <code>null</code> + * if the OA is a business service + * + * @return <code><InfoboxReadRequest></code> as String + */ + public String build(boolean slVersion12, boolean businessService, String identityLinkDomainIdentifier) { + + String slPrefix; + String slNsDeclaration; + + if (slVersion12) { + slPrefix = SL12_PREFIX; + slNsDeclaration = SL12_NS_URI; + } else { + slPrefix = SL10_PREFIX; + slNsDeclaration = SL10_NS_URI; + } + + StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); + sb.append("<"); + sb.append(slPrefix); + sb.append(":InfoboxReadRequest xmlns:"); + sb.append(slPrefix); + sb.append("=\""); + sb.append(slNsDeclaration); + sb.append("\">"); + sb.append("<"); + sb.append(slPrefix); + sb.append(":InfoboxIdentifier>IdentityLink</"); + sb.append(slPrefix); + sb.append(":InfoboxIdentifier>"); + sb.append("<"); + sb.append(slPrefix); + sb.append(":BinaryFileParameters ContentIsXMLEntity=\"true\"/>"); + if (businessService) { + sb.append("<"); + sb.append(slPrefix); + sb.append(":BoxSpecificParameters>"); + sb.append("<"); + sb.append(slPrefix); + sb.append(":IdentityLinkDomainIdentifier>"); + sb.append(identityLinkDomainIdentifier); + sb.append("</sl:IdentityLinkDomainIdentifier>"); + sb.append("</"); + sb.append(slPrefix); + sb.append(":BoxSpecificParameters>"); + } + sb.append("</"); + sb.append(slPrefix); + sb.append(":InfoboxReadRequest>"); + + return sb.toString(); + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxValidatorParamsBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxValidatorParamsBuilder.java new file mode 100644 index 000000000..038e549be --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/InfoboxValidatorParamsBuilder.java @@ -0,0 +1,82 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.util.List; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams; +import at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParamsImpl; +import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameter; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * This class provides one method for building parameters needed for + * validating an infobox token. + * + * @author Harald Bratko + */ +public class InfoboxValidatorParamsBuilder { + + // hide the default constructor + private InfoboxValidatorParamsBuilder() { + } + + /** + * Builds the parameters passed to the validator class for validating an infobox token. + * + * @param session The actual Authentication session. + * @param verifyInfoboxParameter The configuration parameters for the infobox. + * @param infoboxTokenList Contains the infobox token to be validated. + * @param hideStammzahl Indicates whether source pins (<code>Stammzahl</code>en) + * should be hidden in any SAML attributes returned by + * an infobox validator. + * + * @return Parameters for validating an infobox token. + */ + public static InfoboxValidatorParams buildInfoboxValidatorParams( + AuthenticationSession session, + VerifyInfoboxParameter verifyInfoboxParameter, + List infoboxTokenList, + boolean hideStammzahl) + { + InfoboxValidatorParamsImpl infoboxValidatorParams = new InfoboxValidatorParamsImpl(); + IdentityLink identityLink = session.getIdentityLink(); + + // the infobox token to validate + infoboxValidatorParams.setInfoboxTokenList(infoboxTokenList); + // configuration parameters + infoboxValidatorParams.setTrustProfileID(verifyInfoboxParameter.getTrustProfileID()); + infoboxValidatorParams.setSchemaLocations(verifyInfoboxParameter.getSchemaLocations()); + infoboxValidatorParams.setApplicationSpecificParams(verifyInfoboxParameter.getApplicationSpecificParams()); + // authentication session parameters + infoboxValidatorParams.setBkuURL(session.getBkuURL()); + infoboxValidatorParams.setTarget(session.getTarget()); + infoboxValidatorParams.setBusinessApplication(session.getBusinessService()); + // parameters from the identity link + infoboxValidatorParams.setFamilyName(identityLink.getFamilyName()); + infoboxValidatorParams.setGivenName(identityLink.getGivenName()); + infoboxValidatorParams.setDateOfBirth(identityLink.getDateOfBirth()); + if (verifyInfoboxParameter.getProvideStammzahl()) { + infoboxValidatorParams.setIdentificationValue(identityLink.getIdentificationValue()); + } + infoboxValidatorParams.setIdentificationType(identityLink.getIdentificationType()); + infoboxValidatorParams.setPublicKeys(identityLink.getPublicKey()); + if (verifyInfoboxParameter.getProvideIdentityLink()) { + Element identityLinkElem = (Element)identityLink.getSamlAssertion().cloneNode(true); + if (!verifyInfoboxParameter.getProvideStammzahl()) { + Element identificationValueElem = + (Element)XPathUtils.selectSingleNode(identityLinkElem, IdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH); + if (identificationValueElem != null) { + identificationValueElem.getFirstChild().setNodeValue(""); + } + } + infoboxValidatorParams.setIdentityLink(identityLinkElem); + } + infoboxValidatorParams.setHideStammzahl(hideStammzahl); + return infoboxValidatorParams; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/PersonDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/PersonDataBuilder.java new file mode 100644 index 000000000..819ed79bb --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/PersonDataBuilder.java @@ -0,0 +1,59 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Builder for the <code>lt;pr:Person></code> element to be inserted + * in the authentication data <code>lt;saml:Assertion></code>. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class PersonDataBuilder { + + /** + * Constructor for PersonDataBuilder. + */ + public PersonDataBuilder() { + super(); + } + /** + * Builds the <code><pr:Person></code> element.<br/> + * Utilizes the parsed <code><prPerson></code> from the identity link + * and the information regarding inclusion of <code>"Stammzahl"</code> in the + * <code><pr:Person></code> data. + * + * @param identityLink <code>IdentityLink</code> containing the + * attribute <code>prPerson</code> + * @param provideStammzahl true if <code>"Stammzahl"</code> is to be included; + * false otherwise + * @return the <code><pr:Person></code> element as a String + * @throws BuildException on any error + */ + public String build(IdentityLink identityLink, boolean provideStammzahl) + throws BuildException { + + try { + Element prPerson = (Element)identityLink.getPrPerson().cloneNode(true); + if (! provideStammzahl) { + Node prIdentification = XPathUtils.selectSingleNode(prPerson, "pr:Identification/pr:Value"); + //remove IdentificationValue + prIdentification.getFirstChild().setNodeValue(""); + } + String xmlString = DOMUtils.serializeNode(prPerson); + return xmlString; + } + catch (Exception ex) { + throw new BuildException( + "builder.00", + new Object[] {"PersonData", ex.toString()}, + ex); + } + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLArtifactBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLArtifactBuilder.java new file mode 100644 index 000000000..27e19e830 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLArtifactBuilder.java @@ -0,0 +1,60 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.io.ByteArrayOutputStream; +import java.security.MessageDigest; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.Base64Utils; + +/** + * Builder for the SAML artifact, as defined in the + * Browser/Artifact profile of SAML. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SAMLArtifactBuilder { + + /** + * Constructor for SAMLArtifactBuilder. + */ + public SAMLArtifactBuilder() { + super(); + } + + /** + * Builds the SAML artifact, encoded BASE64. + * <ul> + * <li><code>TypeCode</code>: <code>0x0001</code>.</li> + * <li><code>SourceID</code>: SHA-1 hash of the authURL</li> + * <li><code>AssertionHandle</code>: SHA-1 hash of the <code>MOASessionID</code></li> + * </ul> + * @param authURL URL auf the MOA-ID Auth component to be used for construction + * of <code>SourceID</code> + * @param sessionID <code>MOASessionID</code> to be used for construction + * of <code>AssertionHandle</code> + * @return the 42-byte SAML artifact, encoded BASE64 + */ + public String build(String authURL, String sessionID) throws BuildException { + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] sourceID = md.digest(authURL.getBytes()); + byte[] assertionHandle = md.digest(sessionID.getBytes()); + ByteArrayOutputStream out = new ByteArrayOutputStream(42); + out.write(0); + out.write(1); + out.write(sourceID, 0, 20); + out.write(assertionHandle, 0, 20); + byte[] samlArtifact = out.toByteArray(); + String samlArtifactBase64 = Base64Utils.encode(samlArtifact); + return samlArtifactBase64; + } + catch (Throwable ex) { + throw new BuildException( + "builder.00", + new Object[] {"SAML Artifact, MOASessionID=" + sessionID, ex.toString()}, + ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLResponseBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLResponseBuilder.java new file mode 100644 index 000000000..64cb16181 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SAMLResponseBuilder.java @@ -0,0 +1,91 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import java.text.MessageFormat; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Builder for the <code>lt;samlp:Response></code> used for passing + * result and status information from the <code>GetAuthenticationData</code> + * web service. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SAMLResponseBuilder implements Constants { + /** XML - Template for samlp:Response */ + private static final String RESPONSE = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + + "<samlp:Response xmlns:samlp=\"" + SAMLP_NS_URI + "\" xmlns:saml=\"" + SAML_NS_URI + "\"" + + " ResponseID=\"{0}\" InResponseTo=\"{1}\" MajorVersion=\"1\" MinorVersion=\"0\" IssueInstant=\"{2}\">" + + " <samlp:Status>" + + " <samlp:StatusCode Value=\"{3}\">" + + " {4}" + + " </samlp:StatusCode>" + + " <samlp:StatusMessage>{5}</samlp:StatusMessage>" + + " </samlp:Status>" + + " {6}" + + "</samlp:Response>"; + /** XML - Template for samlp:StatusCode */ + private static final String SUB_STATUS_CODE = + "<samlp:StatusCode Value=\"{0}\"></samlp:StatusCode>"; + + /** + * Constructor for SAMLResponseBuilder. + */ + public SAMLResponseBuilder() { + super(); + } + /** + * Builds the SAML response. + * @param responseID response ID + * @param inResponseTo request ID of <code>lt;samlp:Request></code> responded to + * @param issueInstant current timestamp + * @param statusCode status code + * @param subStatusCode sub-status code refining the status code; may be <code>null</code> + * @param statusMessage status message + * @param samlAssertion SAML assertion representing authentication data + * @return SAML response as a DOM element + */ + public Element build( + String responseID, + String inResponseTo, + String issueInstant, + String statusCode, + String subStatusCode, + String statusMessage, + String samlAssertion) + throws BuildException { + + try { + String xmlSubStatusCode = + subStatusCode == null ? + "" : + MessageFormat.format(SUB_STATUS_CODE, new Object[] {subStatusCode}); + + String xmlResponse = MessageFormat.format(RESPONSE, new Object[] { + responseID, + inResponseTo, + issueInstant, + statusCode, + xmlSubStatusCode, + statusMessage, + StringUtils.removeXMLDeclaration(samlAssertion) }); + Element domResponse = DOMUtils.parseDocument(xmlResponse, false, ALL_SCHEMA_LOCATIONS, null).getDocumentElement(); + return domResponse; + } + catch (Throwable ex) { + throw new BuildException( + "builder.00", + new Object[] { "samlp:Response", ex.toString() }, + ex); + } + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SelectBKUFormBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SelectBKUFormBuilder.java new file mode 100644 index 000000000..312179e73 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/SelectBKUFormBuilder.java @@ -0,0 +1,63 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import at.gv.egovernment.moa.id.BuildException; + +/** + * Builder for the BKU selection form requesting the user to choose + * a BKU from a list. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SelectBKUFormBuilder extends Builder { + /** private static String NL contains the NewLine representation in Java*/ + private static final String nl = "\n"; + /** special tag in the HTML template to be substituted for the form action which is + * a URL of MOA-ID Auth */ + private static final String ACTION_TAG = "<StartAuth>"; + /** special tag in the HTML template to be substituted for the <code><select;gt;</code> tag + * containing the BKU selection options */ + private static final String SELECT_TAG = "<BKUSelect>"; + /** + * Template for the default html-code to be returned as security-layer-selection to be built + */ + private static final String DEFAULT_HTML_TEMPLATE = + "<html>" + nl + + "<head>" + nl + + "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">" + nl + + "<title>Auswahl der Bürgerkartenumgebung</title>" + nl + + "</head>" + nl + + "<body>" + nl + + "<form name=\"BKUSelectionForm\"" + nl + + " action=\"" + ACTION_TAG + "\"" + nl + + " method=\"post\">" + nl + + SELECT_TAG + nl + + " <input type=\"submit\" value=\"Bürgerkartenumgebung auswählen\"/>" + nl + + "</form>" + nl + + "</body>" + nl + + "</html>"; + + /** + * Constructor + */ + public SelectBKUFormBuilder() { + super(); + } + /** + * Method build. Builds the form + * @param htmlTemplate to be used + * @param startAuthenticationURL the url where the startAuthenticationServlet can be found + * @param bkuSelectTag if a special bku should be used + * @return String + * @throws BuildException on any error + */ + public String build(String htmlTemplate, String startAuthenticationURL, String bkuSelectTag) + throws BuildException { + + String htmlForm = htmlTemplate == null ? DEFAULT_HTML_TEMPLATE : htmlTemplate; + htmlForm = replaceTag(htmlForm, ACTION_TAG, startAuthenticationURL, true, 1); + htmlForm = replaceTag(htmlForm, SELECT_TAG, bkuSelectTag, true, 1); + return htmlForm; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/VerifyXMLSignatureRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/VerifyXMLSignatureRequestBuilder.java new file mode 100644 index 000000000..758f28150 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/VerifyXMLSignatureRequestBuilder.java @@ -0,0 +1,206 @@ +package at.gv.egovernment.moa.id.auth.builder; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.Constants; + +/** + * Builder for the <code><VerifyXMLSignatureRequestBuilder></code> structure + * used for sending the DSIG-Signature of the Security Layer card for validating to MOA-SP. + * + * @author Stefan Knirsch + * @version $Id$ + */ +public class VerifyXMLSignatureRequestBuilder { + + /** shortcut for XMLNS namespace URI */ + private static final String XMLNS_NS_URI = Constants.XMLNS_NS_URI; + /** shortcut for MOA namespace URI */ + private static final String MOA_NS_URI = Constants.MOA_NS_URI; + /** The DSIG-Prefix */ + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + + /** The document containing the <code>VerifyXMLsignatureRequest</code> */ + private Document requestDoc_; + /** the <code>VerifyXMLsignatureRequest</code> root element */ + private Element requestElem_; + + + /** + * Builds the body for a <code>VerifyXMLsignatureRequest</code> including the root + * element and namespace declarations. + * + * @throws BuildException If an error occurs on building the document. + */ + public VerifyXMLSignatureRequestBuilder() throws BuildException { + try { + DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + requestDoc_ = docBuilder.newDocument(); + requestElem_ = requestDoc_.createElementNS(MOA_NS_URI, "VerifyXMLSignatureRequest"); + requestElem_.setAttributeNS(XMLNS_NS_URI, "xmlns", MOA_NS_URI); + requestElem_.setAttributeNS(XMLNS_NS_URI, "xmlns:" + Constants.DSIG_PREFIX, Constants.DSIG_NS_URI); + requestDoc_.appendChild(requestElem_); + } catch (Throwable t) { + throw new BuildException( + "builder.00", + new Object[] {"VerifyXMLSignatureRequest", t.toString()}, + t); + } + } + + + /** + * Builds a <code><VerifyXMLSignatureRequest></code> + * from an IdentityLink with a known trustProfileID which + * has to exist in MOA-SP + * @param identityLink - The IdentityLink + * @param trustProfileID - a preconfigured TrustProfile at MOA-SP + * + * @return Element - The complete request as Dom-Element + * + * @throws ParseException + */ + public Element build(IdentityLink identityLink, String trustProfileID) + throws ParseException + { + try { + // build the request + Element dateTimeElem = requestDoc_.createElementNS(MOA_NS_URI, "DateTime"); + requestElem_.appendChild(dateTimeElem); + Node dateTime = requestDoc_.createTextNode(identityLink.getIssueInstant()); + dateTimeElem.appendChild(dateTime); + Element verifiySignatureInfoElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureInfo"); + requestElem_.appendChild(verifiySignatureInfoElem); + Element verifySignatureEnvironmentElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureEnvironment"); + verifiySignatureInfoElem.appendChild(verifySignatureEnvironmentElem); + Element base64ContentElem = requestDoc_.createElementNS(MOA_NS_URI, "Base64Content"); + verifySignatureEnvironmentElem.appendChild(base64ContentElem); + // insert the base64 encoded identity link SAML assertion + String serializedAssertion = identityLink.getSerializedSamlAssertion(); + String base64EncodedAssertion = Base64Utils.encode(serializedAssertion.getBytes("UTF-8")); + //replace all '\r' characters by no char. + StringBuffer replaced = new StringBuffer(); + for (int i = 0; i < base64EncodedAssertion.length(); i ++) { + char c = base64EncodedAssertion.charAt(i); + if (c != '\r') { + replaced.append(c); + } + } + base64EncodedAssertion = replaced.toString(); + Node base64Content = requestDoc_.createTextNode(base64EncodedAssertion); + base64ContentElem.appendChild(base64Content); + // specify the signature location + Element verifySignatureLocationElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureLocation"); + verifiySignatureInfoElem.appendChild(verifySignatureLocationElem); + Node signatureLocation = requestDoc_.createTextNode(DSIG + "Signature"); + verifySignatureLocationElem.appendChild(signatureLocation); + // signature manifest params + Element signatureManifestCheckParamsElem = + requestDoc_.createElementNS(MOA_NS_URI, "SignatureManifestCheckParams"); + requestElem_.appendChild(signatureManifestCheckParamsElem); + signatureManifestCheckParamsElem.setAttribute("ReturnReferenceInputData", "false"); + // add the transforms + Element referenceInfoElem = requestDoc_.createElementNS(MOA_NS_URI, "ReferenceInfo"); + signatureManifestCheckParamsElem.appendChild(referenceInfoElem); + Element[] dsigTransforms = identityLink.getDsigReferenceTransforms(); + for (int i = 0; i < dsigTransforms.length; i++) { + Element verifyTransformsInfoProfileElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifyTransformsInfoProfile"); + referenceInfoElem.appendChild(verifyTransformsInfoProfileElem); + verifyTransformsInfoProfileElem.appendChild(requestDoc_.importNode(dsigTransforms[i], true)); + } + Element returnHashInputDataElem = + requestDoc_.createElementNS(MOA_NS_URI, "ReturnHashInputData"); + requestElem_.appendChild(returnHashInputDataElem); + Element trustProfileIDElem = requestDoc_.createElementNS(MOA_NS_URI, "TrustProfileID"); + trustProfileIDElem.appendChild(requestDoc_.createTextNode(trustProfileID)); + requestElem_.appendChild(trustProfileIDElem); + } catch (Throwable t) { + throw new ParseException("builder.00", + new Object[] { "VerifyXMLSignatureRequest (IdentityLink)" }, t); + } + + return requestElem_; + } + + + /** + * Builds a <code><VerifyXMLSignatureRequest></code> + * from the signed AUTH-Block with a known trustProfileID which + * has to exist in MOA-SP + * @param csr - signed AUTH-Block + * @param verifyTransformsInfoProfileID - allowed verifyTransformsInfoProfileID + * @param trustProfileID - a preconfigured TrustProfile at MOA-SP + * @return Element - The complete request as Dom-Element + * @throws ParseException + */ + public Element build( + CreateXMLSignatureResponse csr, + String[] verifyTransformsInfoProfileID, + String trustProfileID) + throws BuildException { //samlAssertionObject + + try { + // build the request +// requestElem_.setAttributeNS(Constants.XMLNS_NS_URI, "xmlns:" +// + Constants.XML_PREFIX, Constants.XMLNS_NS_URI); + Element verifiySignatureInfoElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureInfo"); + requestElem_.appendChild(verifiySignatureInfoElem); + Element verifySignatureEnvironmentElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureEnvironment"); + verifiySignatureInfoElem.appendChild(verifySignatureEnvironmentElem); + Element xmlContentElem = requestDoc_.createElementNS(MOA_NS_URI, "XMLContent"); + verifySignatureEnvironmentElem.appendChild(xmlContentElem); + xmlContentElem.setAttribute(Constants.XML_PREFIX + ":space", "preserve"); + // insert the SAML assertion + xmlContentElem.appendChild(requestDoc_.importNode(csr.getSamlAssertion(), true)); + // specify the signature location + Element verifySignatureLocationElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureLocation"); + verifiySignatureInfoElem.appendChild(verifySignatureLocationElem); + Node signatureLocation = requestDoc_.createTextNode(DSIG + "Signature"); + verifySignatureLocationElem.appendChild(signatureLocation); + // signature manifest params + Element signatureManifestCheckParamsElem = + requestDoc_.createElementNS(MOA_NS_URI, "SignatureManifestCheckParams"); + requestElem_.appendChild(signatureManifestCheckParamsElem); + signatureManifestCheckParamsElem.setAttribute("ReturnReferenceInputData", "true"); + // add the transform profile IDs + Element referenceInfoElem = requestDoc_.createElementNS(MOA_NS_URI, "ReferenceInfo"); + signatureManifestCheckParamsElem.appendChild(referenceInfoElem); + for (int i = 0; i < verifyTransformsInfoProfileID.length; i++) { + Element verifyTransformsInfoProfileIDElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifyTransformsInfoProfileID"); + referenceInfoElem.appendChild(verifyTransformsInfoProfileIDElem); + verifyTransformsInfoProfileIDElem.appendChild( + requestDoc_.createTextNode(verifyTransformsInfoProfileID[i])); + } + Element returnHashInputDataElem = + requestDoc_.createElementNS(MOA_NS_URI, "ReturnHashInputData"); + requestElem_.appendChild(returnHashInputDataElem); + Element trustProfileIDElem = requestDoc_.createElementNS(MOA_NS_URI, "TrustProfileID"); + trustProfileIDElem.appendChild(requestDoc_.createTextNode(trustProfileID)); + requestElem_.appendChild(trustProfileIDElem); + + } catch (Throwable t) { + throw new BuildException("builder.00", new Object[] { "VerifyXMLSignatureRequest" }, t); + } + + return requestElem_; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java new file mode 100644 index 000000000..90d79a46d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java @@ -0,0 +1,383 @@ +package at.gv.egovernment.moa.id.auth.data; + +import java.util.Date; +import java.util.List; + +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; + +/** + * Session data to be stored between <code>AuthenticationServer</code> API calls. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationSession { + + private static String TARGET_PREFIX_ = Constants.URN_PREFIX_CDID + "+"; + + /** + * session ID + */ + private String sessionID; + /** + * "Geschäftsbereich" the online application belongs to; maybe <code>null</code> + * if the online application is a business application + */ + private String target; + /** + * public online application URL requested + */ + private String oaURLRequested; + /** + * public online application URL prefix + */ + private String oaPublicURLPrefix; + /** + * URL of MOA ID authentication component + */ + private String authURL; + /** + * HTML template URL + */ + private String templateURL; + /** + * URL of the BKU + */ + private String bkuURL; + /** + * identity link read from smartcard + */ + private IdentityLink identityLink; + /** + * authentication block to be signed by the user + */ + private String authBlock; + /** + * timestamp logging when authentication session has been created + */ + private Date timestampStart; + /** + * timestamp logging when identity link has been received + */ + private Date timestampIdentityLink; + /** + * Indicates whether the corresponding online application is a business + * service or not + */ + private boolean businessService; + + /** + * SAML attributes from an extended infobox validation to be appended + * to the SAML assertion delivered to the final online application. + */ + private List extendedSAMLAttributesOA; + + /** + * The boolean value for either a target or a wbPK is provided as + * SAML Attribute in the SAML Assertion or not. + */ + private boolean samlAttributeGebeORwbpk; + + /** + * SAML attributes from an extended infobox validation to be appended + * to the SAML assertion of the AUTHBlock. + */ + private List extendedSAMLAttributesAUTH; + + /** + * The issuing time of the AUTH-Block SAML assertion. + */ + private String issueInstant; + + /** + * Constructor for AuthenticationSession. + * + * @param id Session ID + */ + public AuthenticationSession(String id) { + sessionID = id; + setTimestampStart(); + } + + /** + * Returns the identityLink. + * @return IdentityLink + */ + public IdentityLink getIdentityLink() { + return identityLink; + } + + /** + * Returns the sessionID. + * @return String + */ + public String getSessionID() { + return sessionID; + } + + /** + * Sets the identityLink. + * @param identityLink The identityLink to set + */ + public void setIdentityLink(IdentityLink identityLink) { + this.identityLink = identityLink; + } + + /** + * Sets the sessionID. + * @param sessionId The sessionID to set + */ + public void setSessionID(String sessionId) { + this.sessionID = sessionId; + } + + /** + * Returns the oaURLRequested. + * @return String + */ + public String getOAURLRequested() { + return oaURLRequested; + } + + /** + * Returns the oaURLRequested. + * @return String + */ + public String getPublicOAURLPrefix() { + return oaPublicURLPrefix; + } + + /** + * Returns the BKU URL. + * @return String + */ + public String getBkuURL() { + return bkuURL; + } + + /** + * Returns the target. + * @return String + */ + public String getTarget() { + return target; + } + + /** + * Sets the oaURLRequested. + * @param oaURLRequested The oaURLRequested to set + */ + public void setOAURLRequested(String oaURLRequested) { + this.oaURLRequested = oaURLRequested; + } + + /** + * Sets the oaPublicURLPrefix + * @param oaPublicURLPrefix The oaPublicURLPrefix to set + */ + public void setPublicOAURLPrefix(String oaPublicURLPrefix) { + this.oaPublicURLPrefix = oaPublicURLPrefix; + } + + /** + * Sets the bkuURL + * @param bkuURL The BKU URL to set + */ + public void setBkuURL(String bkuURL) { + this.bkuURL = bkuURL; + } + + /** + * Sets the target. If the target includes the target prefix, the prefix will be stripped off. + * @param target The target to set + */ + public void setTarget(String target) { + if (target != null && target.startsWith(TARGET_PREFIX_)) + { + // If target starts with prefix "urn:publicid:gv.at:cdid+"; remove prefix + this.target = target.substring(TARGET_PREFIX_.length()); + Logger.debug("Target prefix stripped off; resulting target: " + this.target); + } + else + { + this.target = target; + } + } + + /** + * Returns the authURL. + * @return String + */ + public String getAuthURL() { + return authURL; + } + + /** + * Sets the authURL. + * @param authURL The authURL to set + */ + public void setAuthURL(String authURL) { + this.authURL = authURL; + } + + /** + * Returns the authBlock. + * @return String + */ + public String getAuthBlock() { + return authBlock; + } + + /** + * Sets the authBlock. + * @param authBlock The authBlock to set + */ + public void setAuthBlock(String authBlock) { + this.authBlock = authBlock; + } + + /** + * Returns the timestampIdentityLink. + * @return Date + */ + public Date getTimestampIdentityLink() { + return timestampIdentityLink; + } + + /** + * Returns the businessService. + * @return <code>true</code> if the corresponding online application is + * a business application, otherwise <code>false</code> + */ + public boolean getBusinessService() { + return businessService; + } + + /** + * Sets the businessService variable. + * @param businessService the value for setting the businessService variable. + */ + public void setBusinessService(boolean businessService) { + this.businessService = businessService; + } + + /** + * Returns the timestampStart. + * @return Date + */ + public Date getTimestampStart() { + return timestampStart; + } + + /** + * Sets the current date as timestampIdentityLink. + */ + public void setTimestampIdentityLink() { + timestampIdentityLink = new Date(); + } + + /** + * Sets the current date as timestampStart. + */ + public void setTimestampStart() { + timestampStart = new Date(); + } + + /** + * @return template URL + */ + public String getTemplateURL() { + return templateURL; + } + + /** + * @param string the template URL + */ + public void setTemplateURL(String string) { + templateURL = string; + } + + /** + * Returns the SAML Attributes to be appended to the AUTHBlock. Maybe <code>null</code>. + * + * @return The SAML Attributes to be appended to the AUTHBlock. Maybe <code>null</code>. + */ + public List getExtendedSAMLAttributesAUTH() { + return extendedSAMLAttributesAUTH; + } + + /** + * Sets the SAML Attributes to be appended to the AUTHBlock. + * + * @param extendedSAMLAttributesAUTH The SAML Attributes to be appended to the AUTHBlock. + */ + public void setExtendedSAMLAttributesAUTH( + List extendedSAMLAttributesAUTH) { + this.extendedSAMLAttributesAUTH = extendedSAMLAttributesAUTH; + } + + /** + * Returns the SAML Attributes to be appended to the SAML assertion + * delivered to the online application. Maybe <code>null</code>. + * + * @return The SAML Attributes to be appended to the SAML assertion + * delivered to the online application + */ + public List getExtendedSAMLAttributesOA() { + return extendedSAMLAttributesOA; + } + + /** + * Sets the SAML Attributes to be appended to the SAML assertion + * delivered to the online application. + * + * @param extendedSAMLAttributesOA The SAML Attributes to be appended to the SAML + * assertion delivered to the online application. + */ + public void setExtendedSAMLAttributesOA( + List extendedSAMLAttributesOA) { + this.extendedSAMLAttributesOA = extendedSAMLAttributesOA; + } + + /** + * Returns the boolean value for either a target or a wbPK is + * provided as SAML Attribute in the SAML Assertion or not. + * + * @return true either a target or a wbPK is provided as SAML Attribute + * in the SAML Assertion or false if not. + */ + public boolean getSAMLAttributeGebeORwbpk() { + return this.samlAttributeGebeORwbpk; + } + + /** + * Sets the boolean value for either a target or a wbPK is + * provided as SAML Attribute in the SAML Assertion or not. + * + * @param samlAttributeGebeORwbpk The boolean for value either a target or + * wbPK is provided as SAML Attribute in the SAML Assertion or not. + */ + public void setSAMLAttributeGebeORwbpk(boolean samlAttributeGebeORwbpk) { + this.samlAttributeGebeORwbpk = samlAttributeGebeORwbpk; + } + + /** + * Returns the issuing time of the AUTH-Block SAML assertion. + * + * @return The issuing time of the AUTH-Block SAML assertion. + */ + public String getIssueInstant() { + return issueInstant; + } + + /** + * Sets the issuing time of the AUTH-Block SAML assertion. + * + * @param issueInstant The issueInstant to set. + */ + public void setIssueInstant(String issueInstant) { + this.issueInstant = issueInstant; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/CreateXMLSignatureResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/CreateXMLSignatureResponse.java new file mode 100644 index 000000000..d121f2c55 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/CreateXMLSignatureResponse.java @@ -0,0 +1,71 @@ +package at.gv.egovernment.moa.id.auth.data; + +import org.w3c.dom.Element; + +/** + * This bean saves all information of the CreateXMLSignature-Response: + * a {@link SAMLAttribute} array, the SamlAssertion-Element and the + * saml NameIdentifier + * + * @author Stefan Knirsch + * @version $Id$ + * + */ +public class CreateXMLSignatureResponse { + /** the samlNameIdentifier */ +private String samlNameIdentifier; + /** an array of saml-attributes */ +private SAMLAttribute[] samlAttributes; + /** + * the original saml:Assertion-Element + */ + private Element samlAssertion; +/** + * Returns the samlAssertion. + * @return Element + */ +public Element getSamlAssertion() { + return samlAssertion; +} + +/** + * Returns the samlAttribute. + * @return SAMLAttribute[] + */ +public SAMLAttribute[] getSamlAttributes() { + return samlAttributes; +} + +/** + * Returns the samlNameIdentifier. + * @return String + */ +public String getSamlNameIdentifier() { + return samlNameIdentifier; +} + +/** + * Sets the samlAssertion. + * @param samlAssertion The samlAssertion to set + */ +public void setSamlAssertion(Element samlAssertion) { + this.samlAssertion = samlAssertion; +} + +/** + * Sets the samlAttribute. + * @param samlAttributes The samlAttributes to set + */ +public void setSamlAttributes(SAMLAttribute[] samlAttributes) { + this.samlAttributes = samlAttributes; +} + +/** + * Sets the samlNameIdentifier. + * @param samlNameIdentifier The samlNameIdentifier to set + */ +public void setSamlNameIdentifier(String samlNameIdentifier) { + this.samlNameIdentifier = samlNameIdentifier; +} + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttribute.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttribute.java new file mode 100644 index 000000000..795079227 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttribute.java @@ -0,0 +1,73 @@ +package at.gv.egovernment.moa.id.auth.data; + +/** + * A SAML-Attribute to be appended to the final SAML-Assertion + * that will be passed to the online application. + */ +public interface ExtendedSAMLAttribute { + /** + * Add this attribute only to the SAML-Assertion + * passed to the online application, but not to + * the AUTH-Block. + */ + public final static int NOT_ADD_TO_AUTHBLOCK = 0; + /** + * Add this attribute to both, the AUTH-Block and the + * final SAML-Assertion passed to the online application. + */ + public final static int ADD_TO_AUTHBLOCK = 1; + /** + * Add this attribute to only the AUTH-Block, but not + * to the final SAML-Assertion passed to the online application. + */ + public final static int ADD_TO_AUTHBLOCK_ONLY = 2; + + /** + * The value of the SAML-Attribute. This must be either a + * <code>org.w3c.Element</code> or a <code>java.lang.String</code> + * object. Each other type will be ignored. <br> + * If, for example, the type of the actual SAML-Attribute is a + * <code><xsd:boolean></code> the value must be either the String + * <code>"true"</code> or <code>"false"</code>. + * Or the <code><xsd:integer></code> number <code>273</code> + * has to be the String <code>"273"</code>. + * + * @return The value of the SAML-Attribute. Must not be <code>null</code>. + */ + public Object getValue(); + + /** + * The name of the SAML-Attribute. + * + * @return The name of the SAML-Attribute. Must not be <code>null</code>. + */ + public String getName(); + + /** + * The namespace of the SAML-Attribute. + * An application will use the context specific namespace URI for the attribute it returns. + * However, if the application cannot explicitely assign a namespace URI, the + * {@link at.gv.egovernment.moa.util.Constants#MOA_NS_URI default} MOA namespace URI + * should be used. + * + * @return The namespace of the SAML-Attribute. Must not be <code>null</code>. + */ + public String getNameSpace(); + + /** + * Specifies if this SAML-Attribute should be added to the AUTH-Block. + * <br> + * Depending on the returned value, this SAML-Attribute should be only added to the + * final SAML-Assertion passed to the online application (0), to both, the final + * assertion and the AUTH-Block (1) or to the AUTH-Block only (2). + * + * @return <ul> + * <li>0 - add this SAML-Attribute to the final SAML-Assertion only</li> + * <li>1 - add this SAML-Attribute to both, the final SAML-Assertion and the + * AUTH-Block</li> + * <li>2 - add this SAML-Attribute to the AUTH-Block only + * </ul> + */ + public int getAddToAUTHBlock(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttributeImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttributeImpl.java new file mode 100644 index 000000000..e7e490924 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/ExtendedSAMLAttributeImpl.java @@ -0,0 +1,137 @@ +package at.gv.egovernment.moa.id.auth.data; + +/** + * This class contains SAML attributes to be appended to the SAML assertion delivered to + * the Online application. + * + * @author Harald Bratko + */ +public class ExtendedSAMLAttributeImpl implements ExtendedSAMLAttribute { + + /** + * The value of this SAML attribute. Must be either of type <code>java.lang.String</code> + * or <code>org.w3c.Element</code>. + */ + protected Object value_; + + /** + * The name of this SAML attribute. + */ + protected String name_; + + /** + * The namespace URI of this SAML attribute. + */ + protected String namespace_; + + /** + * Specifies whether this SAML attribute should be appended to AUTH Block. + */ + protected int addToAUTHBlock_; + + /** + * Sets this ExtendedSAMLAttribute. + * @param name The name of this SAML Attribute. + * @param value The value of this SAML Attribute. Must be either of type + * <code>java.lang.String</code> or <code>org.w3c.dom.Element</code>. + * @param namespace The namespace of this SAML Attribute. + * @param addToAUTHBlock Specifies if this SAML Attribute should be added to the AUTHBlock. + * The following values are allowed: + * <ul> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#ADD_TO_AUTHBLOCK} + * </li> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#NOT_ADD_TO_AUTHBLOCK} + * </li> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#ADD_TO_AUTHBLOCK_ONLY} + * </li> + * </ul> + * + */ + public ExtendedSAMLAttributeImpl(String name, Object value, String namespace, int addToAUTHBlock) { + name_ = name; + value_ = value; + namespace_ = namespace; + addToAUTHBlock_ = addToAUTHBlock; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#getValue() + */ + public Object getValue() { + return value_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#getName() + */ + public String getName() { + return name_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#getNameSpace() + */ + public String getNameSpace() { + return namespace_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#getAddToAUTHBlock() + */ + public int getAddToAUTHBlock() { + return addToAUTHBlock_; + } + + /** + * Specifies if this SAML Attribute should be added to the AUTHBlock. + * + * @param addToAUTHBlock One of the following values: + * <ul> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#ADD_TO_AUTHBLOCK} + * </li> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#NOT_ADD_TO_AUTHBLOCK} + * </li> + * <li> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#ADD_TO_AUTHBLOCK_ONLY} + * </li> + * </ul> + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute#ADD_TO_AUTHBLOCK} + */ + public void setAddToAUTHBlock(int addToAUTHBlock) { + addToAUTHBlock_ = addToAUTHBlock; + } + + /** + * Sets the name of this SAML attribute. + * + * @param name The name of this SAML attribute. + */ + public void setName(String name) { + name_ = name; + } + + /** + * Sets the namespace of this SAML attribute. + * + * @param namespace The namespace to set. + */ + public void setNamespace(String namespace) { + namespace_ = namespace; + } + + /** + * Sets the value of this SAML attribute. + * + * @param value The value of this SAML Attribute. Must be either of type + * <code>java.lang.String</code> or <code>org.w3c.dom.Element</code>. + */ + public void setValue(Object value) { + value_ = value; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/IdentityLink.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/IdentityLink.java new file mode 100644 index 000000000..844451035 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/IdentityLink.java @@ -0,0 +1,266 @@ +package at.gv.egovernment.moa.id.auth.data; + +import java.io.IOException; +import java.security.PublicKey; + +import javax.xml.transform.TransformerException; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.util.DOMUtils; + + +/** + * Data contained in an identity link issued by BMI, relevant to the MOA ID component. + * <br><code>"IdentityLink"</code> is the translation of <code>"Personenbindung"</code>. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class IdentityLink { + /** + * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>. + */ + private String identificationValue; + /** + * <code>"identificationType"</code> type of the identificationValue in the IdentityLink. + */ + private String identificationType; + /** + * first name + */ + private String givenName; + /** + * family name + */ + private String familyName; + + /** + * The name as (givenName + familyName) + */ + private String name; + /** + * date of birth + */ + private String dateOfBirth; + /** + * the original saml:Assertion-Element + */ + private Element samlAssertion; + /** + * the serializes saml:Assertion + */ + private String serializedSamlAssertion; + /** + * Element /saml:Assertion/saml:AttributeStatement/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/pr:Person + */ + private Element prPerson; + /** + * we need for each dsig:Reference Element all + * transformation elements + */ + private Element[] dsigReferenceTransforms; + + /** + * The issuing time of the identity link SAML assertion. + */ + private String issueInstant; + + /** + * we need all public keys stored in + * the identity link + */ + private PublicKey[] publicKey; + + /** + * Constructor for IdentityLink + */ + public IdentityLink() { + } + + /** + * Returns the dateOfBirth. + * @return Calendar + */ + public String getDateOfBirth() { + return dateOfBirth; + } + + /** + * Returns the familyName. + * @return String + */ + public String getFamilyName() { + return familyName; + } + + /** + * Returns the givenName. + * @return String + */ + public String getGivenName() { + return givenName; + } + + /** + * Returns the name. + * @return The name. + */ + public String getName() { + if (name == null) { + name = givenName + " " + familyName; + } + return name; + } + + /** + * Returns the identificationValue. + * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>. + * @return String + */ + public String getIdentificationValue() { + return identificationValue; + } + + /** + * Returns the identificationType. + * <code>"identificationType"</code> type of the identificationValue in the IdentityLink. + * @return String + */ + public String getIdentificationType() { + return identificationType; + } + + /** + * Sets the dateOfBirth. + * @param dateOfBirth The dateOfBirth to set + */ + public void setDateOfBirth(String dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + /** + * Sets the familyName. + * @param familyName The familyName to set + */ + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + /** + * Sets the givenName. + * @param givenName The givenName to set + */ + public void setGivenName(String givenName) { + this.givenName = givenName; + } + + /** + * Sets the identificationValue. + * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>. + * @param identificationValue The identificationValue to set + */ + public void setIdentificationValue(String identificationValue) { + this.identificationValue = identificationValue; + } + + /** + * Sets the Type of the identificationValue. + * @param identificationType The type of identificationValue to set + */ + public void setIdentificationType(String identificationType) { + this.identificationType = identificationType; + } + + /** + * Returns the samlAssertion. + * @return Element + */ + public Element getSamlAssertion() { + return samlAssertion; + } + + /** + * Returns the samlAssertion. + * @return Element + */ + public String getSerializedSamlAssertion() { + return serializedSamlAssertion; + } + + /** + * Sets the samlAssertion and the serializedSamlAssertion. + * @param samlAssertion The samlAssertion to set + */ + public void setSamlAssertion(Element samlAssertion) throws TransformerException, IOException { + this.samlAssertion = samlAssertion; + this.serializedSamlAssertion = DOMUtils.serializeNode(samlAssertion); + } + + /** + * Returns the dsigReferenceTransforms. + * @return Element[] + */ + public Element[] getDsigReferenceTransforms() { + return dsigReferenceTransforms; + } + + /** + * Sets the dsigReferenceTransforms. + * @param dsigReferenceTransforms The dsigReferenceTransforms to set + */ + public void setDsigReferenceTransforms(Element[] dsigReferenceTransforms) { + this.dsigReferenceTransforms = dsigReferenceTransforms; + } + + /** + * Returns the publicKey. + * @return PublicKey[] + */ + public PublicKey[] getPublicKey() { + return publicKey; + } + + /** + * Sets the publicKey. + * @param publicKey The publicKey to set + */ + public void setPublicKey(PublicKey[] publicKey) { + this.publicKey = publicKey; + } + + /** + * Returns the prPerson. + * @return Element + */ + public Element getPrPerson() { + return prPerson; + } + + /** + * Sets the prPerson. + * @param prPerson The prPerson to set + */ + public void setPrPerson(Element prPerson) { + this.prPerson = prPerson; + } + + /** + * Returns the issuing time of the identity link SAML assertion. + * + * @return The issuing time of the identity link SAML assertion. + */ + public String getIssueInstant() { + return issueInstant; + } + + /** + * Sets the issuing time of the identity link SAML assertion. + * + * @param issueInstant The issueInstant to set. + */ + public void setIssueInstant(String issueInstant) { + this.issueInstant = issueInstant; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxToken.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxToken.java new file mode 100644 index 000000000..6b1f24aba --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxToken.java @@ -0,0 +1,65 @@ +package at.gv.egovernment.moa.id.auth.data; + +import org.w3c.dom.Element; + +/** + * Contains an infobox token included in an <code>InfoboxReadResponse</code>. + * Depending on whether the token is extracted from an <code>XMLContent</code> or a + * <code>Base64Content</code> it is either returned as DOM element + * ({@link #getXMLToken()}) or base64 encoded string ({@link #getBase64Token()}). + * + * @author Harald Bratko + */ +public interface InfoboxToken { + + /** + * The key of the corresponding infobox. + * This is the value of <code>Key</code> attribute of the <code><Pair></code> child + * element in an <code><AssocArrayData></code> content of an InfoboxReadResponse. + * Maybe <code>null</code> if the InfoboxReadResponse conatains <code>BinaryFileData</code>. + * + * + * @return The key identifier of the corresponding infobox. + */ + public String getKey(); + + /** + * Specifies if this token is the first token (e.g in an array of tokens) included in an + * <code>InfoboxReadResponse</code>. If <code>true</code> this token is the token to be + * validated by a corresponding + * {@link at.gv.egovernment.moa.id.auth.validator.InfoboxValidator InfoboxValidator}. + * If <code>false</code> this token maybe needed to validate the primary token. + * + * @return <code>True</code> if this token is the first token. + */ + public boolean isPrimary(); + + /** + * Returns the infobox token. + * Maybe <code>null</code> if the token is returned by method {@link #getBase64Token()} + * as base64 encoded string. + * <br> + * Note that this token is <code><i><b>not</b></i></code> validated against the + * application specific schema (e.g. Mandates schema in the mandates context). + * Thus the validating application <code><i><b>has to</b></i></code> validate the token + * against the appropriate schema. + * + * @return The infobox token. If <code>null</code> the token is returned by method + * {@link #getBase64Token()} as base64 encoded string. + */ + public Element getXMLToken(); + + /** + * Returns the infobox token. + * Maybe <code>null</code> if the token is returned by method {@link #getXMLToken()} + * as a DOM element. + * <br> + * Note, that the base64 encoded string actually may include more than one infobox + * elements. + * + * @return The infobox token. If <code>null</code> the token is returned by method + * {@link #getBase64Token()} as base64 encoded string. + */ + public String getBase64Token(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxTokenImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxTokenImpl.java new file mode 100644 index 000000000..f1ff30a8a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxTokenImpl.java @@ -0,0 +1,129 @@ +package at.gv.egovernment.moa.id.auth.data; + +import org.w3c.dom.Element; + +/** + * This class contains an infobox token. + * + * @see at.gv.egovernment.moa.id.auth.data.InfoboxToken + * + * @author Harald Bratko + */ +public class InfoboxTokenImpl implements InfoboxToken { + + /** + * The key of the infobox token. + */ + private String key_; + + /** + * Specifies whether this token is the primary (first in an array) token. + */ + private boolean primary_; + + /** + * The infobox token. + */ + private Element xmlToken_; + + /** + * The base64 encoded infobox token. + */ + private String base64Token_; + + /** + * Sets an XML infobox token. + * + * @param key The key of the infobox token. + * @param primary <code>True</code> this token is the primary (e.g .first in an array) + * token, otherwise <code>false</code> + * @param xmlToken The infobox token. + */ + public InfoboxTokenImpl(String key, boolean primary, Element xmlToken) { + key_ = key; + primary_ = primary; + xmlToken_ = xmlToken; + base64Token_ = null; + } + + /** + * Sets a base64 encoded infobox token. + * + * @param key The key of the infobox token. + * @param primary <code>True</code> this token is the primary (e.g .first in an array) + * token, otherwise <code>false</code> + * @param base64Token The base64 encoded infobox token. + */ + public InfoboxTokenImpl(String key, boolean primary, String base64Token) { + key_ = key; + primary_ = primary; + base64Token_ = base64Token; + xmlToken_ = null; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxToken#getKey() + */ + public String getKey() { + return key_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxToken#isPrimary() + */ + public boolean isPrimary() { + return primary_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxToken#getXMLToken() + */ + public Element getXMLToken() { + return xmlToken_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxToken#getBase64Token() + */ + public String getBase64Token() { + return base64Token_; + } + + /** + * Sets the key of the infobox token. + * + * @param key The key of the infobox token. + */ + public void setKey(String key) { + key_ = key; + } + + /** + * Specifies whether this token is the primary (e.g. first in an array) token. + * + * @param primary <code>True</code> this token is the primary (e.g .first in an array) + * token, otherwise <code>false</code>. + */ + public void setPrimary(boolean primary) { + primary_ = primary; + } + + /** + * Sets the base64 encoded token. + * + * @param base64Token The base64 encoded token. + */ + public void setBase64Token(String base64Token) { + base64Token_ = base64Token; + } + + /** + * Sets the infobox token. + * + * @param xmlToken The infobox token. + */ + public void setXmlToken(Element xmlToken) { + xmlToken_ = xmlToken; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResult.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResult.java new file mode 100644 index 000000000..b8dd7f18e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResult.java @@ -0,0 +1,57 @@ +package at.gv.egovernment.moa.id.auth.data; + + +/** + * Includes the result of an extended infobox validation. + * + * If validation succeeds, an array of + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute ExtendedSAMLAttributes} + * maybe provided. Each of these SAML-Attributes will be either appended to the + * final SAML-Assertion passed to the online application or to the AUTH-Block, + * or to both. + * <br> + * If validation fails the implementing class has to provide a short error message. + * + * @author Harald Bratko + */ +public interface InfoboxValidationResult { + + /** + * The method returns <code>true</code> if validation succeeds. In that case + * method {@link #getExtendedSamlAttributes()} may provide an array of + * {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute + * ExtendedSAMLAttributes} that should be appended to the final SAML-Assertion or the + * AUTH-Block or to both. + * <br> + * The method returns <code>false</code> if validation fails. In that case + * method {@link #getErrorMessage()} has to provide a short error description. + * + * @return <code>True</code> if validation succeeds, + * otherwise <code>false</code>. + */ + public boolean isValid(); + + /** + * Returns an array of {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute + * ExtendedSAMLAttributes} that should be added to the SAML-Assertion + * provided to the online application. + * The SAML-Attributes in that array will be added to the final + * SAML-Assertion, the AUTH-Block, or both, exactly in the order as they are arranged + * in the array this method returns. + * + * @return An array of {@link at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute + * ExtendedSAMLAttributes} that should be added to the SAML-Assertion + * provided to the online application, the AUTH-Block, or both. If no attributes should + * be added this array maybe <code>null</code> or empty. + */ + public ExtendedSAMLAttribute[] getExtendedSamlAttributes(); + + /** + * A short error description that should be displayed by MOA-ID if + * validation of the InfoBoxReadResponse fails. + * + * @return An short error message if validation fails. + */ + public String getErrorMessage(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResultImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResultImpl.java new file mode 100644 index 000000000..97f52fb55 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidationResultImpl.java @@ -0,0 +1,101 @@ +package at.gv.egovernment.moa.id.auth.data; + + +/** + * Default implementation of the {@link InfoboxValidationResult} interface. + * + * @author Harald Bratko + */ +public class InfoboxValidationResultImpl implements InfoboxValidationResult { + + /** + * Indicates whether the validation was successful or not. + */ + protected boolean valid_; + + /** + * The error message. + */ + protected String errorMessage_; + + /** + * The SAML attributes returned by the infobox validator. + */ + protected ExtendedSAMLAttribute[] extendedSamlAttributes_; + + /** + * Empty constructor. + */ + public InfoboxValidationResultImpl() { + } + + /** + * Constructor to set all values. + * + * @param valid Global validation result. + * @param extendedSamlAttributes SAML attributes that should be appended to the final + * <code>SAML Assertion</code> or to the <code>AUTH Block</code> + * or to both. + * @param errorMessage An error message if infobox validation fails. + */ + public InfoboxValidationResultImpl( + boolean valid, + ExtendedSAMLAttribute[] extendedSamlAttributes, + String errorMessage) + { + valid_ = valid; + extendedSamlAttributes_ = extendedSamlAttributes; + errorMessage_ = errorMessage; + } + + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult#getErrorMessage() + */ + public String getErrorMessage() { + return errorMessage_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult#getExtendedSamlAttributes() + */ + public ExtendedSAMLAttribute[] getExtendedSamlAttributes() { + return extendedSamlAttributes_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult#isValid() + */ + public boolean isValid() { + return valid_; + } + + /** + * Sets the error message if validation fails.. + * + * @param errorMessage The error message to set. + */ + public void setErrorMessage(String errorMessage) { + errorMessage_ = errorMessage; + } + + /** + * Sets the SAML attributes returned by the infobox validatior.. + * + * @param extendedSamlAttributes The SAML attributes returned by the infobox validator. + */ + public void setExtendedSamlAttributes(ExtendedSAMLAttribute[] extendedSamlAttributes) { + extendedSamlAttributes_ = extendedSamlAttributes; + } + + /** + * Sets validation result.. + * + * @param valid <code>True</code> if the infobox could be validated successfully, + * otherwise <code>false</code>. + */ + public void setValid(boolean valid) { + valid_ = valid; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParams.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParams.java new file mode 100644 index 000000000..c7a557290 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParams.java @@ -0,0 +1,172 @@ +package at.gv.egovernment.moa.id.auth.data; + +import java.security.PublicKey; +import java.util.List; + +import org.w3c.dom.Element; + +/** + * Parameters for validating an infobox. + * + * This interface is used by MOA-ID to provide parameters to an + * {link at.gv.egovernment.moa.id.auth.validator.InfoboxValidator + * InfoboxValidator}. + * + * @author Harald Bratko + */ +public interface InfoboxValidatorParams { + + /** + * Returns a list of {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} + * objects. The first token in this list is the one to be validated. Each further token + * maybe needed to validate this first token. + * + * @return A list of {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} + * objects. + */ + public List getInfoboxTokenList(); + + /** + * Returns the ID of the trust profile to be used for validating + * certificates. Maybe ignored by a validator, if no certificates + * has to be validated. + * + * @return The ID of a trust profile. + */ + public String getTrustProfileID(); + + /** + * Returns schema location URIs that may be needed by the + * validator to parse infobox tokens. + * Each entry in the list is a {@link Schema} specifying the location + * of an XML schema. + * + * @return A list of {@link Schema} objects each of them specifying the + * location of an XML schema. + */ + public List getSchemaLocations(); + + /** + * Returns the URL of the BKU. + * Maybe needed by a validator. + * + * @return The url of the BKU. + */ + public String getBkuURL(); + + /** + * Returns the target parameter. + * <code>null</code> in the case of a business service. + * + * @return The target parameter. + */ + public String getTarget(); + + /** + * Returns <code>true</code> if the application is a business + * service, otherwise <code>false</code>. This may be useful + * for the validating application. + * + * @return <code>True</code> if the application is a business + * service, otherwise <code>false</code> + */ + public boolean getBusinessApplication(); + + /** + * Returns the family name from the identity link. + * Maybe needed by a validator. + * + * @return The family name from the identity link. + */ + public String getFamilyName(); + + /** + * Returns the given name from the identity link. + * Maybe needed by a validator. + * + * @return The given name from the identity link. + */ + public String getGivenName(); + + /** + * The date of birth from the identity link. + * The method returns the value of the <pr:DateOfBirth> + * element from the identity link. + * Maybe needed by a validator. + * + * @return The date of birth from the identity link. + */ + public String getDateOfBirth(); + + /** + * Returns he identification value from the identity + * link. This may be the <code>Stammzahl</code> + * in the case of a public application or the + * <code>wbPK</code> in the case of a business + * application. This parameter is only returned + * if specified within the config file. + * + * @return The identification value from the identity link. + */ + public String getIdentificationValue(); + + /** + * Returns the type of the identification value + * from the identity link. This may be + * especially of interest for business + * applications. + * + * @return The type of the identification value + * from the identity link. + */ + public String getIdentificationType(); + + /** + * Returns the public keys from the identity link. + * Maybe needed by the application. + * + * @return PublicKey[] The public keys from the + * identity link. + */ + public PublicKey[] getPublicKeys(); + + /** + * Returns the identity link. + * A validator may need other data from the identity link, than + * family name, given name, date of birth and identification value. + * The identity link element is only returned if specified within the + * config file. + * + * @return The identity link. + */ + public Element getIdentityLink(); + + /** + * Indicates whether source pins (<code>Stammzahl</code>en) should be hidden or not. + * If an online application lying behind MOA-ID is not allowed to get source pins + * (<code>Stammzahl</code>en), any source pins within <code>SAML attributes</code> + * returned by the validator must suppressed:<br> + * If the parameter <code>getHideStammzahl</code> is <code>true</code>, then the validator + * <b>MUST</b> hide (replace by an empty string) any source pin (<code>Stammzahl</code>) + * that may be included in a <code>SAML attribute</code> returned by the validator. + * + * @return <code>true</code> if source pins (<code>Stammzahl</code>en) must be hidden, + * otherwise <code>false</code>. + */ + public boolean getHideStammzahl(); + + /** + * Returns application specific parameters. + * Each child element of this element contains + * a validating application specific parameter. The + * element is passed as specified within the config + * file and its up to the implementing class to + * parse and interprete its children. + * + * @return Application specific parameters. + */ + public Element getApplicationSpecificParams(); + +} + + diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParamsImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParamsImpl.java new file mode 100644 index 000000000..80ba5995f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/InfoboxValidatorParamsImpl.java @@ -0,0 +1,348 @@ +package at.gv.egovernment.moa.id.auth.data; + +import java.security.PublicKey; +import java.util.List; + +import org.w3c.dom.Element; + +/** + * Parameters for validating an infobox. + * + * This interface is used by MOA-ID to provide parameters to an + * {link at.gv.egovernment.moa.id.auth.validator.InfoboxValidator + * InfoboxValidator}. + * + * @author Harald Bratko + */ +public class InfoboxValidatorParamsImpl implements InfoboxValidatorParams { + + /** + * A list of {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} objects. + * The first token in this list is the one to be validated. Each further token + * maybe needed to validate this first token. + */ + protected List infoboxTokenList_; + + /** + * The ID of the trust profile used for validating certificates. + */ + protected String trustProfileID_; + + /** + * The locations of schemas that maybe needed for validating infobox tokens. + */ + protected List schemaLocations_; + + /** + * The URL of the BKU. + */ + protected String bkuURL_; + + /** + * Specifies whether the current online application is a business or a public application. + */ + protected boolean businessApplication_; + + /** + * The target parameter. + */ + protected String target_; + + /** + * The family name from the identity link. + */ + protected String familyName_; + + /** + * The given name from the identity link. + */ + protected String givenName_; + + /** + * The date of birth from the identity link. + */ + protected String dateOfBirth_; + + /** + * The date of identification value. + */ + protected String identificationValue_; + + /** + * The identification type. + */ + protected String identificationType_; + + /** + * The public keys from the identity link. + */ + protected PublicKey[] publicKeys_; + + /** + * The identity link. + */ + protected Element identityLink_; + + /** + * Indicates whether source pins (<code>Stammzahl</code>en) must be hidden or not. + */ + protected boolean hideStammzahl_; + + /** + * Application specific parameters. + */ + protected Element applicationSpecificParams_; + + /** + * Empty constructor. + */ + public InfoboxValidatorParamsImpl() { + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getInfoboxTokenList() + */ + public List getInfoboxTokenList() { + return infoboxTokenList_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getTrustProfileID() + */ + public String getTrustProfileID() { + return trustProfileID_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getSchemaLocations() + */ + public List getSchemaLocations() { + return schemaLocations_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getBkuURL() + */ + public String getBkuURL() { + return bkuURL_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getTarget() + */ + public String getTarget() { + return target_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getBusinessApplication() + */ + public boolean getBusinessApplication() { + return businessApplication_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getFamilyName() + */ + public String getFamilyName() { + return familyName_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getGivenName() + */ + public String getGivenName() { + return givenName_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getDateOfBirth() + */ + public String getDateOfBirth() { + return dateOfBirth_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getIdentificationValue() + */ + public String getIdentificationValue() { + return identificationValue_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getIdentificationType() + */ + public String getIdentificationType() { + return identificationType_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getPublicKeys() + */ + public PublicKey[] getPublicKeys() { + return publicKeys_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getIdentityLink() + */ + public Element getIdentityLink() { + return identityLink_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getHideStammzahl() + */ + public boolean getHideStammzahl() { + return hideStammzahl_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams#getApplicationSpecificParams() + */ + public Element getApplicationSpecificParams() { + return applicationSpecificParams_; + } + + /** + * Sets the application specific parameters. + * + * @param applicationSpecificParams The application specific parameters to set. + */ + public void setApplicationSpecificParams(Element applicationSpecificParams) { + applicationSpecificParams_ = applicationSpecificParams; + } + + /** + * Sets the bku URL. + * + * @param bkuURL The bku URL to set. + */ + public void setBkuURL(String bkuURL) { + bkuURL_ = bkuURL; + } + + /** + * Sets the business application parameter. + * + * @param businessApplication The business application parameter to set. + * (<code>True</code> if the application is a business + * application, otherwies <code>false</code>). + */ + public void setBusinessApplication(boolean businessApplication) { + businessApplication_ = businessApplication; + } + + /** + * Sets the date of birth. + * + * @param dateOfBirth The date of birth. + */ + public void setDateOfBirth(String dateOfBirth) { + dateOfBirth_ = dateOfBirth; + } + + /** + * Sets the family name. + * + * @param familyName The family name. + */ + public void setFamilyName(String familyName) { + familyName_ = familyName; + } + + /** + * Sets the given name. + * + * @param givenName The given name. + */ + public void setGivenName(String givenName) { + givenName_ = givenName; + } + + /** + * Sets the identification type. + * + * @param identificationType The identification type. + */ + public void setIdentificationType(String identificationType) { + identificationType_ = identificationType; + } + + /** + * Sets the identification value. + * + * @param identificationValue The identification value. + */ + public void setIdentificationValue(String identificationValue) { + identificationValue_ = identificationValue; + } + + /** + * Sets the identity link. + * + * @param identityLink The identity link. + */ + public void setIdentityLink(Element identityLink) { + identityLink_ = identityLink; + } + + /** + * Sets the infobox token to be validated. + * + * @param infoboxTokenList A list {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} + * objects. + */ + public void setInfoboxTokenList(List infoboxTokenList) { + infoboxTokenList_ = infoboxTokenList; + } + + /** + * Sets the public Keys. + * + * @param publicKeys The public keys. + */ + public void setPublicKeys(PublicKey[] publicKeys) { + publicKeys_ = publicKeys; + } + + /** + * Sets the schema locations. + * + * @param schemaLocations The schema locations. A list of + * {@link Schema} objects. + */ + public void setSchemaLocations(List schemaLocations) { + schemaLocations_ = schemaLocations; + } + + /** + * Sets the target. + * + * @param target The target. + */ + public void setTarget(String target) { + target_ = target; + } + + /** + * Sets the ID of the trust profile used for validating certificates. + * + * @param trustProfileID the ID of the trust profile used for validating certificates. + */ + public void setTrustProfileID(String trustProfileID) { + trustProfileID_ = trustProfileID; + } + + /** + * Sets the {@link #hideStammzahl_} parameter. This indicates whether source pins + * (<code>Stammzahl</code>en) must be hidden or not. + * + * @param hideStammzahl <code>True</code> if source pins (<code>Stammzahl</code>en) should + * be hidden, otherwise <code>false</code>. + */ + public void setHideStammzahl(boolean hideStammzahl) { + hideStammzahl_ = hideStammzahl; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SAMLAttribute.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SAMLAttribute.java new file mode 100644 index 000000000..76ba6366d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SAMLAttribute.java @@ -0,0 +1,79 @@ +package at.gv.egovernment.moa.id.auth.data; + +/** + * This bean saves all data of a single SAMLAttribute: + * the name, value and namespace + * + * @author Stefan Knirsch + * @version $Id$ + * + */ +public class SAMLAttribute { + + /** the name to be stored */ + private String name; + /** the namespace to be stored */ + private String namespace; + /** the value to be stored */ + private Object value; + + /** + * Constructor for SAMLAttribute. + */ + public SAMLAttribute(String name, String namespace, Object value) { + + this.name = name; + this.namespace = namespace; + this.value = value; + + } + + /** + * Returns the name. + * @return String + */ + public String getName() { + return name; + } + + /** + * Returns the namespace. + * @return String + */ + public String getNamespace() { + return namespace; + } + + /** + * Returns the value. + * @return String + */ + public Object getValue() { + return value; + } + + /** + * Sets the name. + * @param name The name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Sets the namespace. + * @param namespace The namespace to set + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + /** + * Sets the value. + * @param value The value to set + */ + public void setValue(Object value) { + this.value = value; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/Schema.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/Schema.java new file mode 100644 index 000000000..c113f16b8 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/Schema.java @@ -0,0 +1,26 @@ +package at.gv.egovernment.moa.id.auth.data; + +/** + * Specifies the location of a schema. + * + * @author Harald Bratko + */ +public interface Schema { + + /** + * The namespace URI of this schema. + * + * @return The namespace of this schema. + */ + public String getNamespace(); + + /** + * The location URI of this schema. + * Relative paths have to be interpreted relative to the + * location of the MOA-ID config file. + * + * @return The location URI of this schema. + */ + public String getSchemaLocation(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SchemaImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SchemaImpl.java new file mode 100644 index 000000000..964725416 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/SchemaImpl.java @@ -0,0 +1,63 @@ +package at.gv.egovernment.moa.id.auth.data; + +/** + * This class specifies the location of a schema. + * + * @author Harald Bratko + */ +public class SchemaImpl implements Schema { + + /** + * The namespace of this schema. + */ + protected String namespace_; + + /** + * The location (URI) of this schema; + */ + protected String schemaLocation_; + + /** + * Sets the namespace and schema location URIS of this schema. + * + * @param namespace The namespace URI of this schema. + * @param schemaLocation The location URI of this schema. + */ + public SchemaImpl(String namespace, String schemaLocation) { + namespace_ = namespace; + schemaLocation_ = schemaLocation; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.Schema#getNamespace() + */ + public String getNamespace() { + return namespace_; + } + + /** + * @see at.gv.egovernment.moa.id.auth.data.Schema#getSchemaLocation() + */ + public String getSchemaLocation() { + return schemaLocation_; + } + + /** + * Sets the namespace. + * + * @param namespace The namespace to set. + */ + public void setNamespace(String namespace) { + namespace_ = namespace; + } + + /** + * Sets the location URI of this schema. + * + * @param schemaLocation The schemaLocation to set. + */ + public void setSchemaLocation(String schemaLocation) { + schemaLocation_ = schemaLocation; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/VerifyXMLSignatureResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/VerifyXMLSignatureResponse.java new file mode 100644 index 000000000..8233d1478 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/VerifyXMLSignatureResponse.java @@ -0,0 +1,177 @@ +package at.gv.egovernment.moa.id.auth.data; + +import iaik.x509.X509Certificate; + +/** + * This bean saves all information of the MOA-SP-Answer + * after the verification of any signature + * + * @author Stefan Knirsch + * @version $Id$ + * + */ +public class VerifyXMLSignatureResponse { + /** The xmlDsigSubjectName to be stored */ + private String xmlDsigSubjectName; + /** The signatureCheckCode to be stored */ + private int signatureCheckCode; + /** The xmlDSIGManifestCheckCode to be stored */ + private int xmlDSIGManifestCheckCode; + /** The xmlDSIGManigest to be stored */ + private boolean xmlDSIGManigest; + /** The certificateCheckCode to be stored */ + private int certificateCheckCode; + /** The publicAuthority to be stored */ + private boolean publicAuthority; + /** The publicAuthorityCode to be stored */ + private String publicAuthorityCode; + /** The qualifiedCertificate to be stored */ + private boolean qualifiedCertificate; + /** The x509certificate to be stored */ + private X509Certificate x509certificate; + + /** + * Returns the certificateCheckCode. + * @return int + */ + public int getCertificateCheckCode() { + return certificateCheckCode; + } + + /** + * Returns the signatureCheckCode. + * @return int + */ + public int getSignatureCheckCode() { + return signatureCheckCode; + } + + /** + * Returns the xmlDSIGManifestCheckCode. + * @return int + */ + public int getXmlDSIGManifestCheckCode() { + return xmlDSIGManifestCheckCode; + } + + /** + * Returns the xmlDsigSubjectName. + * @return String + */ + public String getXmlDsigSubjectName() { + return xmlDsigSubjectName; + } + + /** + * Sets the certificateCheckCode. + * @param certificateCheckCode The certificateCheckCode to set + */ + public void setCertificateCheckCode(int certificateCheckCode) { + this.certificateCheckCode = certificateCheckCode; + } + + /** + * Sets the signatureCheckCode. + * @param signatureCheckCode The signatureCheckCode to set + */ + public void setSignatureCheckCode(int signatureCheckCode) { + this.signatureCheckCode = signatureCheckCode; + } + + /** + * Sets the xmlDSIGManifestCheckCode. + * @param xmlDSIGManifestCheckCode The xmlDSIGManifestCheckCode to set + */ + public void setXmlDSIGManifestCheckCode(int xmlDSIGManifestCheckCode) { + this.xmlDSIGManifestCheckCode = xmlDSIGManifestCheckCode; + } + + /** + * Sets the xmlDsigSubjectName. + * @param xmlDsigSubjectName The xmlDsigSubjectName to set + */ + public void setXmlDsigSubjectName(String xmlDsigSubjectName) { + this.xmlDsigSubjectName = xmlDsigSubjectName; + } + + /** + * Returns the publicAuthorityCode. + * @return int + */ + public String getPublicAuthorityCode() { + return publicAuthorityCode; + } + + /** + * Sets the publicAuthorityCode. + * @param publicAuthorityCode The publicAuthorityCode to set + */ + public void setPublicAuthorityCode(String publicAuthorityCode) { + this.publicAuthorityCode = publicAuthorityCode; + } + + /** + * Returns the qualifiedCertificate. + * @return boolean + */ + public boolean isQualifiedCertificate() { + return qualifiedCertificate; + } + + /** + * Returns the x509certificate. + * @return X509Certificate + */ + public X509Certificate getX509certificate() { + return x509certificate; + } + + /** + * Sets the qualifiedCertificate. + * @param qualifiedCertificate The qualifiedCertificate to set + */ + public void setQualifiedCertificate(boolean qualifiedCertificate) { + this.qualifiedCertificate = qualifiedCertificate; + } + + /** + * Sets the x509certificate. + * @param x509certificate The x509certificate to set + */ + public void setX509certificate(X509Certificate x509certificate) { + this.x509certificate = x509certificate; + } + + /** + * Returns the xmlDSIGManigest. + * @return boolean + */ + public boolean isXmlDSIGManigest() { + return xmlDSIGManigest; + } + + /** + * Sets the xmlDSIGManigest. + * @param xmlDSIGManigest The xmlDSIGManigest to set + */ + public void setXmlDSIGManigest(boolean xmlDSIGManigest) { + this.xmlDSIGManigest = xmlDSIGManigest; + } + + /** + * Returns the publicAuthority. + * @return boolean + */ + public boolean isPublicAuthority() { + return publicAuthority; + } + + /** + * Sets the publicAuthority. + * @param publicAuthority The publicAuthority to set + */ + public void setPublicAuthority(boolean publicAuthority) { + this.publicAuthority = publicAuthority; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/invoke/SignatureVerificationInvoker.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/invoke/SignatureVerificationInvoker.java new file mode 100644 index 000000000..a18cf7322 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/invoke/SignatureVerificationInvoker.java @@ -0,0 +1,92 @@ +package at.gv.egovernment.moa.id.auth.invoke; + +import java.util.Vector; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.api.SignatureVerificationService; +import at.gv.egovernment.moa.spss.api.xmlbind.VerifyXMLSignatureRequestParser; +import at.gv.egovernment.moa.spss.api.xmlbind.VerifyXMLSignatureResponseBuilder; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; + +/** + * Invoker of the <code>SignatureVerification</code> web service of MOA-SPSS.<br> + * Either invokes the web service, or calls the corresponding API, depending on configuration data. + * + * @author Stefan Knirsch + * @version $Id$ + */ +public class SignatureVerificationInvoker { + /** This QName Object identifies the SignatureVerification endpoint of the web service */ + private static final QName SERVICE_QNAME = new QName("SignatureVerification"); + + /** + * Method verifyXMLSignature. + * @param request to be sent + * @return Element with the answer + * @throws ServiceException if an error occurs + */ + public Element verifyXMLSignature(Element request) throws ServiceException { + return doCall(SERVICE_QNAME, request); + } + + /** + * Method doCall. + * @param serviceName the name of the service + * @param request the request to be sent + * @return Element the answer + * @throws ServiceException if an error occurs + */ + protected Element doCall(QName serviceName, Element request) throws ServiceException { + ConnectionParameter authConnParam = null; + try { + Service service = ServiceFactory.newInstance().createService(serviceName); + Call call = service.createCall(); + SOAPBodyElement body = new SOAPBodyElement(request); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + Vector responses; + SOAPBodyElement response; + + String endPoint; + AuthConfigurationProvider authConfigProvider = AuthConfigurationProvider.getInstance(); + authConnParam = authConfigProvider.getMoaSpConnectionParameter(); + //If the ConnectionParameter do NOT exist, we try to get the api to work.... + if (authConnParam != null) { + endPoint = authConnParam.getUrl(); + call.setTargetEndpointAddress(endPoint); + responses = (Vector) call.invoke(serviceName, params); + response = (SOAPBodyElement) responses.get(0); + return response.getAsDOM(); + } + else { + SignatureVerificationService svs = SignatureVerificationService.getInstance(); + VerifyXMLSignatureRequest vsrequest = new VerifyXMLSignatureRequestParser().parse(request); + + VerifyXMLSignatureResponse vsresponse = svs.verifyXMLSignature(vsrequest); + Document result = new VerifyXMLSignatureResponseBuilder().build(vsresponse); + + Logger.setHierarchy("moa.id.auth"); + return result.getDocumentElement(); + } + } + catch (Exception ex) { + if (authConnParam != null) { + throw new ServiceException("service.00", new Object[] { ex.toString()}, ex); + } else { + throw new ServiceException("service.03", new Object[] { ex.toString()}, ex); + } + } + } +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/CreateXMLSignatureResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/CreateXMLSignatureResponseParser.java new file mode 100644 index 000000000..a8b870f04 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/CreateXMLSignatureResponseParser.java @@ -0,0 +1,193 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.traversal.NodeIterator; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.data.SAMLAttribute; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parses an <code><InfoboxReadResponse></code> returned from + * the security layer + * + * @author Stefan Knirsch + * @version $Id$ + */ + +public class CreateXMLSignatureResponseParser { + // + // XPath namespace prefix shortcuts + // + + /** Xpath prefix for reaching SAML Namespaces */ + private static final String SAML = Constants.SAML_PREFIX + ":"; + /** Xpath prefix for reaching XML-DSIG Namespaces */ + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + /** Xpath expression to the root element */ + private static final String ROOT = ":CreateXMLSignatureResponse/"; + /** Xpath expression to the SAML:Assertion element */ + private static final String SAML_ASSERTION_XPATH = ROOT + SAML + "Assertion"; + /** Xpath expression to the SAML:NameIdentifier element */ + private static final String SAML_SUBJECT_NAME_IDENTIFIER_XPATH = SAML_ASSERTION_XPATH + "/" + SAML + "AttributeStatement/" + SAML + "Subject/" + SAML + "NameIdentifier"; + /** Xpath expression to the AttributeStatement element */ + private static final String SAML_ATTRIBUTE_XPATH = SAML_ASSERTION_XPATH + "/" + SAML + "AttributeStatement/" + SAML + "Attribute"; + /** Xpath expression to the AttributeValue element */ + private static final String SAML_ATTRIBUTE_VALUE_XPATH = SAML + "AttributeValue"; + + + /** This is the root element of the CreateXMLsignatureResponse */ + private Element sigResponse_; + + /** + * Parses and validates the document given as string and extracts the + * root element. + * + * @param xmlResponse <code><CreateXMLSignatureResponse></code> as String + * + * @throws AuthenticationException if any authentication error occurs + * @throws ParseException if an element cannot be parsed + */ + public CreateXMLSignatureResponseParser(String xmlResponse) throws AuthenticationException, ParseException { + try { + InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8")); + init(s); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + /** + * Parses and validates the document given as stream and extracts the + * root element. + * + * @param is <code><InfoboxReadResponse></code> as InputStream + * + * @throws AuthenticationException If any authentication error occurs + * @throws ParseException If an element cannot be parsed + */ + public CreateXMLSignatureResponseParser(InputStream is) throws AuthenticationException, ParseException { + init(is); + } + + /** + * Constructor for CreateXMLSignatureResponseParser. + * The incoming Element will be used for further operations + * @param xmlResponse <code><InfoboxReadResponse></code> as InputStream + */ + public CreateXMLSignatureResponseParser(Element xmlResponse) { + sigResponse_ = xmlResponse; + } + + /** + * Initializes the parser. + * Parses and validates the document given as stream and extracts the + * root element. + * + * @param is The CreateXMLSignatureResponse as stream. + * @throws AuthenticationException if an authentication error occurs. + * @throws ParseException If an error occurs on parsing the the document. + */ + private void init(InputStream is) throws AuthenticationException, ParseException { + try { + + Element responseElem = DOMUtils.parseXmlValidating(is); + + if ("CreateXMLSignatureResponse".equals(responseElem.getLocalName())) { + sigResponse_ = responseElem; + } else { + ErrorResponseParser erp = new ErrorResponseParser(responseElem); + throw new AuthenticationException("auth.08", new Object[] { erp.getErrorCode(), erp.getErrorInfo()}); + } + + } catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + /** + * Unmarshalls the <@link sigResponse> to an + * <code><CreateXMLSignatureResponse></code> object. + * + * @return a <code><CreateXMLSignatureResponse></code> object + * @throws ParseException + */ + + public CreateXMLSignatureResponse parseResponse() throws ParseException { + CreateXMLSignatureResponse cResp; + try { + cResp = new CreateXMLSignatureResponse(); + String slPrefix = XPathUtils.getSlPrefix(sigResponse_); + cResp.setSamlNameIdentifier(XPathUtils.getElementValue(sigResponse_, "/" + slPrefix + SAML_SUBJECT_NAME_IDENTIFIER_XPATH, null)); + cResp.setSamlAssertion((Element) XPathUtils.selectSingleNode(sigResponse_, "/" + slPrefix + SAML_ASSERTION_XPATH)); + NodeIterator attrIter = XPathUtils.selectNodeIterator(sigResponse_, "/" + slPrefix + SAML_ATTRIBUTE_XPATH); + Element samlAttr; + List samlAttributes = new ArrayList(); + while ((samlAttr = (Element) attrIter.nextNode()) != null) { + String attrName = XPathUtils.getAttributeValue(samlAttr, "@AttributeName", ""); + String attrNamespace = XPathUtils.getAttributeValue(samlAttr, "@AttributeNamespace", ""); + Object attrValue; + Element attrValueElem = (Element)XPathUtils.selectSingleNode(samlAttr, SAML_ATTRIBUTE_VALUE_XPATH); + attrValue = DOMUtils.getElementFromNodeList(attrValueElem.getChildNodes()); + if (attrValue == null) { + if (null!=attrValueElem.getFirstChild()) { + attrValue = attrValueElem.getFirstChild().getNodeValue(); + } else { + attrValue = ""; + } + } + samlAttributes.add(new SAMLAttribute(attrName, attrNamespace, attrValue)); + } + SAMLAttribute[] result = new SAMLAttribute[samlAttributes.size()]; + samlAttributes.toArray(result); + cResp.setSamlAttributes(result); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + return cResp; + } + +// public CreateXMLSignatureResponse parseResponse() throws ParseException { +// CreateXMLSignatureResponse cResp; +// try { +// cResp = new CreateXMLSignatureResponse(); +// Element samlAssertion = (Element)sigResponse.getElementsByTagNameNS(Constants.SAML_NS_URI, "Assertion").item(0); +// cResp.setSamlAssertion(samlAssertion); +// Element samlAttributeStatement = (Element)samlAssertion.getElementsByTagNameNS(Constants.SAML_NS_URI, "AttributeStatement").item(0); +// Element samlSubject = (Element)samlAttributeStatement.getElementsByTagNameNS(Constants.SAML_NS_URI, "Subject").item(0); +// Element samlNameIdentifier = (Element)samlSubject.getElementsByTagNameNS(Constants.SAML_NS_URI, "NameIdentifier").item(0); +// cResp.setSamlNameIdentifier(samlNameIdentifier.getFirstChild().getNodeValue()); +// NodeList nl = samlAttributeStatement.getElementsByTagNameNS(Constants.SAML_NS_URI, "Attribute"); +// List samlAttributes = new ArrayList(); +// for (int i=0; i<nl.getLength(); i++) { +// Element samlAttribute = (Element)nl.item(i); +// String attrName = samlAttribute.getAttribute("AttributeName"); +// String attrNamespace = samlAttribute.getAttribute("AttributeNamespace"); +// String attrValue = ((Element)samlAttribute.getElementsByTagNameNS(Constants.SAML_NS_URI, "AttributeValue").item(0)).getFirstChild().getNodeValue(); +// samlAttributes.add(new SAMLAttribute(attrName, attrNamespace, attrValue)); +// } +// SAMLAttribute[] result = new SAMLAttribute[samlAttributes.size()]; +// samlAttributes.toArray(result); +// cResp.setSamlAttributes(result); +// } +// catch (Throwable t) { +// throw new ParseException("parser.01", new Object[] { t.toString()}, t); +// } +// return cResp; +// } + + + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ErrorResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ErrorResponseParser.java new file mode 100644 index 000000000..e3c54095d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ErrorResponseParser.java @@ -0,0 +1,72 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.util.DOMUtils; + +/** + * Parses an <code><ErrorResponse></code>. + * + * @author Stefan Knirsch + * @version $Id$ + */ + +public class ErrorResponseParser { + + /** + * The error code included in this error response. + * <code>1000</code> is used as default value, if some problems occur on + * evaluating the error response. + */ + private String errorCode_ = "1000"; + + /** + * The error info included in this error response. + * <code><Unklassifizierter Fehler.></code> is used as default value, + * if some problems occur on evaluating the error response. + */ + private String errorInfo_ = "Unklassifizierter Fehler."; + + + /** + * This Constructor extracts the error code and error info included in this + * error response. + * + * @param errorElement The error element. This is the root element of + * the error response. + */ + public ErrorResponseParser(Element errorElement) throws ParseException { + if (errorElement != null) { + String namespace = errorElement.getNamespaceURI(); + NodeList nl = errorElement.getElementsByTagNameNS(namespace, "ErrorCode"); + if (nl.getLength() == 1) { + errorCode_ = ((Element)nl.item(0)).getFirstChild().getNodeValue(); + } + nl = errorElement.getElementsByTagNameNS(namespace, "Info"); + if (nl.getLength() == 1) { + errorInfo_ = ((Element)nl.item(0)).getFirstChild().getNodeValue(); + } + } + } + + /** + * Returns the error code included in this error response. + */ + public String getErrorCode() { + return errorCode_ ; + } + + /** + * Returns the information included in this error response. + * @return The error infomation String + */ + public String getErrorInfo() { + return errorInfo_ ; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ExtendedInfoboxReadResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ExtendedInfoboxReadResponseParser.java new file mode 100644 index 000000000..e493f07fb --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/ExtendedInfoboxReadResponseParser.java @@ -0,0 +1,157 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.InfoboxToken; +import at.gv.egovernment.moa.id.auth.data.InfoboxTokenImpl; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; + +/** + * Parses and unmarshales <code>InfoboxReadResponse<code>. + * This parser is especially used for parsing additional responses (additional to that + * one containing the <code>IdentityLink</code> retuned from the BKU as an answer of + * a <code><PushInfobox></code> request. + */ +public class ExtendedInfoboxReadResponseParser { + + /** + * Hide default constructor. + */ + private ExtendedInfoboxReadResponseParser() { + } + + /** + * Parses and unmarshales the given <code>infoboxReadResponse</code> to a list of + * {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} objects. + * The method parses the given <code>infoboxReadResponse</code> + * + * @param infoboxReadResponse The infobox read response to be unmarshaled. + * @param infoboxName The name of the infobox the reponse corresponds to. + * + * @return A list of {@link at.gv.egovernment.moa.id.auth.data.InfoboxToken InfoboxToken} + * objects. Maybe empty. + * + * @throws ParseException If an error occurs on parsing and unmarshaling the response. + */ + public static List parseInfoboxReadResponse(String infoboxReadResponse, String infoboxName) + throws ParseException + { + Element infoboxReadResponseElem = null; + try { + Document doc = + DOMUtils.parseDocument(infoboxReadResponse, true, Constants.ALL_SCHEMA_LOCATIONS, null); + infoboxReadResponseElem = doc.getDocumentElement(); + } catch (Exception e) { + Logger.error("InfoboxReadResponse for \"" + infoboxName + + "\"-infobox could not be parsed successfully: " + e.getMessage()); + throw new ParseException("parser.01", new Object[] {infoboxName + "-InfoboxReadResponse"}); + } + + Vector infoboxTokenList = new Vector(); + + if (infoboxReadResponseElem != null) { + // avoid using namespace URI or prefix, because it might change within the response + // (e.g.: sl11-namespace, some child sl10-namespace + List infoboxReadResponseChildren = DOMUtils.getChildElements(infoboxReadResponseElem); + String key = null; + boolean primary = true; + Element infoboxReadResponseChild = (Element)infoboxReadResponseChildren.get(0); + String infoboxReadResponseChildName = infoboxReadResponseChild.getLocalName(); + if (infoboxReadResponseChildName.equals("AssocArrayData")) { + // get the <Pair> child elements from the <AssocArrayData> element + List assocArrayPairs = DOMUtils.getChildElements(infoboxReadResponseChild); + Iterator assocArrayPairIt = assocArrayPairs.iterator(); + int pairCount = 0; + // step through the <Pair> elemnts + while (assocArrayPairIt.hasNext()) { + Element assocArrayPair = (Element)assocArrayPairIt.next(); + // check if the element actually a "Pair" element and not only a "key" + if (assocArrayPair.getLocalName().equals("Key")) { + // do not accept only a Key + throw new ParseException("parser.07", new Object[] {infoboxName}); + } + key = assocArrayPair.getAttribute("Key"); + if (pairCount > 0) { + primary = false; + } + pairCount++; + infoboxTokenList.addAll(getTokenFromXMLOrBase64Content(assocArrayPair, infoboxName, key, primary)); + } + + } else if (infoboxReadResponseChildName.equals("BinaryFileData")) { + infoboxTokenList.addAll(getTokenFromXMLOrBase64Content(infoboxReadResponseChild, infoboxName, null, true)); + } + } + return infoboxTokenList; + } + + /** + * Unmarshales the <code><XMLContent></code> or + * <code><Base64Content></code> child of the given element to a list of + * infobox token. + * + * @param contentParent The elment including the <code><XMLContent></code> or + * <code><Base64Content></code> child to unmarshal the + * infobox token from. + * @param infoboxName The name of the infobox. + * @param key The key of an <code>AssocArrayData-Pair</code>. + * Maybe <code>null</code>. + * @param primary Specifies whether this token is the first (e.g. in an + * AssocArrayData) token. + * + * @return A infobox token list. + * + * @throws ParseException If the <code>contentParent</code> has no <code><XMLContent></code> + * or <code><Base64Content></code> child or the + * <code><XMLContent></code> is empty. + */ + public static List getTokenFromXMLOrBase64Content( + Element contentParent, + String infoboxName, + String key, + boolean primary) + throws ParseException + { + Vector tokenList = new Vector(); + // get the <XMLContent> or <Base64Content> + List content = DOMUtils.getChildElements(contentParent); + if (content.size() == 1) { + Element contentElem = (Element)content.get(0); + if (contentElem.getLocalName().equals("XMLContent")) { + List xmlContentChildren = DOMUtils.getChildElements(contentElem); + if (xmlContentChildren.size() == 0) { + throw new ParseException("parser.06", new Object[] {infoboxName, "Inhalt", "XMLContent"}); + } + int xmlCount = 0; + Iterator contentIt = xmlContentChildren.iterator(); + while (contentIt.hasNext()) { + Element xmlToken = (Element)contentIt.next(); + if (xmlCount > 0) { + primary = false; + } + InfoboxToken infoboxToken = new InfoboxTokenImpl(key, primary, xmlToken); + tokenList.add(infoboxToken); + xmlCount++; + } + } else { + String base64Token = contentElem.getFirstChild().getNodeValue(); + InfoboxToken infoboxToken = new InfoboxTokenImpl(key, primary, base64Token); + tokenList.add(infoboxToken); + } + } else { + throw new ParseException("parser.06", + new Object[] {infoboxName, "XMLContent oder Base64Content", contentParent.getLocalName()}); + } + return tokenList; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/IdentityLinkAssertionParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/IdentityLinkAssertionParser.java new file mode 100644 index 000000000..d8a57fd2f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/IdentityLinkAssertionParser.java @@ -0,0 +1,319 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.traversal.NodeIterator; + +import at.gv.egovernment.moa.id.ECDSAConverterException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.util.ECDSAKeyValueConverter; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parses an identity link <code><saml:Assertion></code> + * @author Paul Ivancsics + * @version $Id$ + */ +public class IdentityLinkAssertionParser { + + // + // XPath namespace prefix shortcuts + // + + /** Xpath prefix for reaching PersonData Namespaces */ + private static final String PDATA = Constants.PD_PREFIX + ":"; + /** Xpath prefix for reaching SAML Namespaces */ + private static final String SAML = Constants.SAML_PREFIX + ":"; + /** Xpath prefix for reaching XML-DSIG Namespaces */ + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + /** Xpath prefix for reaching ECDS Namespaces */ + private static final String ECDSA = Constants.ECDSA_PREFIX + ":"; + /** Xpath expression to the root element */ + private static final String ROOT = ""; + /** Xpath expression to the SAMLSubjectConfirmationData element */ + private static final String SAML_SUBJECT_CONFIRMATION_DATA_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Subject/" + + SAML + + "SubjectConfirmation/" + + SAML + + "SubjectConfirmationData"; + /** Xpath expression to the PersonData element */ + private static final String PERSON_XPATH = + SAML_SUBJECT_CONFIRMATION_DATA_XPATH + + "/" + + PDATA + + "Person"; + /** Xpath expression to the PersonData GivenName element */ + private static final String PERSON_GIVEN_NAME_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "Name/" + + PDATA + + "GivenName"; + /** Xpath expression to the PersonData FamilyName element */ + private static final String PERSON_FAMILY_NAME_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "Name/" + + PDATA + + "FamilyName"; + /** Xpath expression to the PersonData DateOfBirth element */ + private static final String PERSON_DATE_OF_BIRTH_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "DateOfBirth"; + /** Xpath expression to the Identification element */ + private static final String PERSON_IDENT_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "Identification"; + + /** Xpath expression to the Identification Value element */ + public static final String PERSON_IDENT_VALUE_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "Identification/" + + PDATA + + "Value"; + + /** Xpath expression to the Identification Value element */ + private static final String PERSON_IDENT_TYPE_XPATH = + PERSON_XPATH + + "/" + + PDATA + + "Identification/" + + PDATA + + "Type"; + + /** Xpath expression to the RSAKeyValue element */ + private static final String RSA_KEY_VALUE_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Attribute/" + + SAML + + "AttributeValue/" + + DSIG + + "RSAKeyValue"; + + /** Xpath expression to the ECKeyValue element */ + private static final String ECDSA_KEY_VALUE_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Attribute/" + + SAML + + "AttributeValue/" + + ECDSA + + "ECDSAKeyValue"; + + + /** Xpath expression to the RSA Modulus element */ + private static final String RSA_KEY_MODULUS_XPATH = DSIG + "Modulus"; + /** Xpath expression to the RSA Exponent element */ + private static final String RSA_KEY_EXPONENT_XPATH = DSIG + "Exponent"; + /** Xpath expression to the DSIG X509Certificate element */ + private static final String DSIG_CERTIFICATES_XPATH = + ROOT + + DSIG + + "Signature/" + + DSIG + + "KeyInfo/" + + DSIG + + "X509Data/" + + DSIG + + "X509Certificate"; + /** Xpath expression to the DSIG Transforms element */ + private static final String DSIG_REFERENCE_TRANSFORMATION_XPATH = + ROOT + + DSIG + + "Signature/" + + DSIG + + "SignedInfo/" + + DSIG + + "Reference/" + + DSIG + + "Transforms"; + + /** The IssueInstant attribute of the SAML assertion */ + private static final String ISSUE_INSTANT_ATTR = "IssueInstant"; + + /**This is the root element of the XML-Document provided by the Security Layer Card*/ + private Element assertionElem; + + /** + * Constructor for <code>IdentityLinkAssertionParser</code>. + * A DOM-representation of the incoming String will be created + * @param xmlAssertion <code><saml:Assertion></code> as String + * @throws ParseException on any parsing error + */ + public IdentityLinkAssertionParser(String xmlAssertion) throws ParseException { + try { + InputStream s = new ByteArrayInputStream(xmlAssertion.getBytes("UTF-8")); + assertionElem = DOMUtils.parseXmlValidating(s); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + /** + * Sets the <@link assertionElem>. + * @param xmlAssertion the assertion element + * @throws ParseException on any parsing error + */ + public IdentityLinkAssertionParser(Element xmlAssertion) throws ParseException { + assertionElem = xmlAssertion; + } + + /** + * Constructor for <code>IdentityLinkAssertionParser</code>. + * A DOM-representation of the incoming Inputstream will be created + * @param xmlAssertion <code><saml:Assertion></code> as InputStream + * @throws ParseException on any parsing error + */ + public IdentityLinkAssertionParser(InputStream xmlAssertion) throws Exception { + try { + assertionElem = DOMUtils.parseXmlValidating(xmlAssertion); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + } + + /** + * Parses the identity link from the <code><saml:Assertion></code> + * @return Identity link + * @throws ParseException on any parsing error + */ + + public IdentityLink parseIdentityLink() throws ParseException { + IdentityLink identityLink; + try { + identityLink = new IdentityLink(); + identityLink.setSamlAssertion(assertionElem); + identityLink.setIssueInstant(assertionElem.getAttribute(ISSUE_INSTANT_ATTR)); + identityLink.setPrPerson((Element) + XPathUtils.selectSingleNode(assertionElem, PERSON_XPATH)); + identityLink.setIdentificationValue( + XPathUtils.getElementValue(assertionElem, PERSON_IDENT_VALUE_XPATH, "")); + identityLink.setIdentificationType( + XPathUtils.getElementValue(assertionElem, PERSON_IDENT_TYPE_XPATH, "")); + identityLink.setGivenName( + XPathUtils.getElementValue(assertionElem, PERSON_GIVEN_NAME_XPATH, "")); + identityLink.setFamilyName( + XPathUtils.getElementValue(assertionElem, PERSON_FAMILY_NAME_XPATH, "")); + identityLink.setDateOfBirth( + XPathUtils.getElementValue(assertionElem, PERSON_DATE_OF_BIRTH_XPATH, "")); + NodeIterator dsigRefTransforms = + XPathUtils.selectNodeIterator(assertionElem, DSIG_REFERENCE_TRANSFORMATION_XPATH); + List transElems = new ArrayList(); + Element transformsElem; + while ((transformsElem = (Element) dsigRefTransforms.nextNode()) != null) { + transElems.add(transformsElem); + } + Element[] result = new Element[transElems.size()]; + transElems.toArray(result); + identityLink.setDsigReferenceTransforms(result); + + identityLink.setPublicKey(getPublicKeys()); + + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + + return identityLink; + } + + /** + * Parses an array of Public Keys from the <code><InfoboxReadResponse></code> + * @return RSAPublicKey[] + * @throws IOException can occur when decoding the base64 values of the modulus and exponent + */ + public PublicKey[] getPublicKeys() throws IOException, ECDSAConverterException{ + + + List pubKeys = new ArrayList(); + //Try to get RSA-Keys + NodeIterator rsaIter = + XPathUtils.selectNodeIterator(assertionElem, Constants.nSMap, RSA_KEY_VALUE_XPATH); + Element rsaElem; + + while ((rsaElem = (Element) rsaIter.nextNode()) != null) { + String modulus = + XPathUtils.getElementValue(rsaElem, RSA_KEY_MODULUS_XPATH, ""); + String exponent = + XPathUtils.getElementValue(rsaElem, RSA_KEY_EXPONENT_XPATH, ""); + + RSAPublicKey resPub = + new iaik.security.rsa.RSAPublicKey( + new BigInteger(1, Base64Utils.decode(modulus, true)), + new BigInteger(1, Base64Utils.decode(exponent, true))); + pubKeys.add(resPub); + } + + //Try to get ECDSA-Keys + NodeIterator ecdsaIter = + XPathUtils.selectNodeIterator(assertionElem, Constants.nSMap, ECDSA_KEY_VALUE_XPATH); + Element ecdsaElem; + PublicKey ecPubKey = null; + while ((ecdsaElem = (Element) ecdsaIter.nextNode()) != null) { + try { + ecPubKey = ECDSAKeyValueConverter.element2ECDSAPublicKey(ecdsaElem); + pubKeys.add(ecPubKey); + } + catch(Exception e) { + throw new ECDSAConverterException("parser.03", new Object[] { e.toString() }, e); + } + } + + PublicKey[] result = new PublicKey[pubKeys.size()]; + pubKeys.toArray(result); + return result; + + } + /** + * Parses a string array of decoded base64 certificates from + * the <code><InfoboxReadResponse></code> found in the dsig-signature + * @return String[] with raw-certificates from the dsig-signature keyinfo + * @throws Exception + */ + public String[] getCertificates() throws Exception { + List certs = new ArrayList(); + NodeIterator rsaIter = + XPathUtils.selectNodeIterator(assertionElem, DSIG_CERTIFICATES_XPATH); + Element certElem; + while ((certElem = (Element) rsaIter.nextNode()) != null) { + String content = DOMUtils.getText(certElem); + certs.add(new String(Base64Utils.decode(content, true))); + } + String[] result = new String[certs.size()]; + certs.toArray(result); + return result; + + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/InfoboxReadResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/InfoboxReadResponseParser.java new file mode 100644 index 000000000..e59c88ddc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/InfoboxReadResponseParser.java @@ -0,0 +1,165 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parses an <code><InfoboxReadResponse></code>. + * + * @author Stefan Knirsch + * @version $Id$ + */ + +public class InfoboxReadResponseParser { + + /** This is the root element of the XML-Document provided by the Security Layer Card*/ + private Element infoBoxElem_; + + /** + * Parses and validates the document given as string and extracts the + * root element. + * + * @param xmlResponse <code><InfoboxReadResponse></code> as String + * @throws ParseException If an element cannot be parsed + * @throws AuthenticationException If any authentication error occurs + */ + public InfoboxReadResponseParser(String xmlResponse) throws ParseException, AuthenticationException { + + try { + InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8")); + init(s); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + /** + * Parses and validates the document given as stream and extracts the + * root element. + * + * @param is <code><InfoboxReadResponse></code> as InputStream + * @throws ParseException If an element cannot be parsed + * @throws AuthenticationException If any authentication error occurs + */ + public InfoboxReadResponseParser(InputStream is) throws ParseException, AuthenticationException { + init(is); + } + + /** + * Initializes the parser. + * Parses and validates the document given as stream and extracts the + * root element. + * + * @param is The InfoBoxReadResponse as stream. + * @throws AuthenticationException If an authentication error occurs. + * @throws ParseException If an error occurs on parsing the the document. + */ + private void init(InputStream is) throws AuthenticationException, ParseException { + try { + + Element responseElem = DOMUtils.parseXmlValidating(is); + + if ("InfoboxReadResponse".equals(responseElem.getLocalName())) { + infoBoxElem_ = responseElem; + } else { + ErrorResponseParser erp = new ErrorResponseParser(responseElem); + throw new AuthenticationException("auth.08", new Object[] { erp.getErrorCode(), erp.getErrorInfo()}); + } + + } catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + + + /** + * Parses the embedded <code><saml:Assertion></code> element from <code><InfoboxReadResponse></code> + * @return <code><saml:Assertion></code> as String + * @throws ParseException on any parsing error + */ +// public String parseSAMLAssertion() throws ParseException { +// try { +// +// String slPrefix = XPathUtils.getSlPrefix(infoBoxElem_); +// StringBuffer sb = new StringBuffer("/"); +// sb.append(slPrefix); +// sb.append(":InfoboxReadResponse/"); +// sb.append(slPrefix); +// sb.append(":BinaryFileData/"); +// sb.append(slPrefix); +// sb.append(":XMLContent/"); +// sb.append(Constants.SAML_PREFIX); +// sb.append(":Assertion"); +// String samlAssertionXPath = sb.toString(); +// Element samlAssertion = (Element) XPathUtils.selectSingleNode(infoBoxElem_, samlAssertionXPath); +// return DOMUtils.serializeNode(samlAssertion); +// +// } +// catch (Throwable t) { +// throw new ParseException("parser.01", new Object[] { t.toString()}, t); +// } +// } + + /** + * Parses the embedded <code><saml:Assertion></code> element from <code><InfoboxReadResponse></code> + * @return <code><saml:Assertion></code> as String + * @throws ParseException on any parsing error + */ + public Element parseSAMLAssertion() throws ParseException { + try { + + String slPrefix = XPathUtils.getSlPrefix(infoBoxElem_); + StringBuffer sb = new StringBuffer("/"); + sb.append(slPrefix); + sb.append(":InfoboxReadResponse/"); + sb.append(slPrefix); + sb.append(":BinaryFileData/"); + sb.append(slPrefix); + sb.append(":XMLContent/"); + sb.append(Constants.SAML_PREFIX); + sb.append(":Assertion"); + String samlAssertionXPath = sb.toString(); + Element samlAssertion = (Element) XPathUtils.selectSingleNode(infoBoxElem_, samlAssertionXPath); + return samlAssertion; + + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString()}, t); + } + } + + /** + * Parses the identity link from the <code><saml:Assertion></code> + * @return Identity link + * @throws ParseException on any parsing error + */ + +// public IdentityLink parseIdentityLink() throws ParseException { +// String samlAssertionString = parseSAMLAssertion(); +// IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertionString); +// return ilParser.parseIdentityLink(); +// } + + /** + * Parses the identity link from the <code><saml:Assertion></code> + * @return Identity link + * @throws ParseException on any parsing error + */ + public IdentityLink parseIdentityLink() throws ParseException { + Element samlAssertion = parseSAMLAssertion(); + IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertion); + return ilParser.parseIdentityLink(); + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/SAMLArtifactParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/SAMLArtifactParser.java new file mode 100644 index 000000000..7c4c01abe --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/SAMLArtifactParser.java @@ -0,0 +1,58 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import java.io.IOException; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.util.Base64Utils; + +/** + * Parser for a SAML artifact. + * @author Paul Ivancsics + * @version $Id$ + */ +public class SAMLArtifactParser { + /** byte array containing the SamlArtifact bytes */ + private byte[] samlArtifactBytes; + + /** + * Constructor + * @param samlArtifact as String + * @throws ParseException on any parsing error + */ + public SAMLArtifactParser(String samlArtifact) throws ParseException { + try { + samlArtifactBytes = Base64Utils.decode(samlArtifact, false); + } + catch (IOException ex) { + throw new ParseException("parser.02", new Object[] {ex.toString()}, ex); + } + } + /** + * Parses the type code. + * @return type code + * @throws ParseException when SAML artifact is invalid + */ + public byte[] parseTypeCode() throws ParseException { + try { + byte[] typeCode = new byte[] {samlArtifactBytes[0], samlArtifactBytes[1]}; + return typeCode; + } + catch (Throwable ex) { + throw new ParseException("parser.02", new Object[] {ex.toString()}, ex); + } + } + /** + * Parses the assertion handle. + * @return assertion handle + * @throws ParseException when SAML artifact is invalid + */ + public String parseAssertionHandle() throws ParseException { + try { + return new String(samlArtifactBytes, 22, 20); + } + catch (Throwable ex) { + throw new ParseException("parser.02", new Object[] {ex.toString()}, ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/VerifyXMLSignatureResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/VerifyXMLSignatureResponseParser.java new file mode 100644 index 000000000..4c49afb76 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/VerifyXMLSignatureResponseParser.java @@ -0,0 +1,156 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import iaik.utils.Base64InputStream; +import iaik.x509.X509Certificate; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.*; +import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parses a <code><VerifyXMLSignatureResponse></code> returned by + * MOA-SPSS. + * This class implements the Singleton pattern + * + * @author Stefan Knirsch + * @version $Id$ + */ + + +public class VerifyXMLSignatureResponseParser { + // + // XPath namespace prefix shortcuts + // + /** Xpath prefix for reaching MOA Namespaces */ + private static final String MOA = Constants.MOA_PREFIX + ":"; + /** Xpath prefix for reaching DSIG Namespaces */ + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + /** Xpath expression to the root element */ + private static final String ROOT = "/" + MOA + "VerifyXMLSignatureResponse/"; + + /** Xpath expression to the X509SubjectName element */ + private static final String DSIG_SUBJECT_NAME_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + + DSIG + "X509SubjectName"; + /** Xpath expression to the X509Certificate element */ + private static final String DSIG_X509_CERTIFICATE_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + + DSIG + "X509Certificate"; + /** Xpath expression to the PublicAuthority element */ + private static final String PUBLIC_AUTHORITY_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + + MOA + "PublicAuthority"; + /** Xpath expression to the PublicAuthorityCode element */ + private static final String PUBLIC_AUTHORITY_CODE_XPATH = + PUBLIC_AUTHORITY_XPATH + "/" + MOA + "Code"; + /** Xpath expression to the QualifiedCertificate element */ + private static final String QUALIFIED_CERTIFICATE_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + + MOA + "QualifiedCertificate"; + + /** Xpath expression to the SignatureCheckCode element */ + private static final String SIGNATURE_CHECK_CODE_XPATH = + ROOT + MOA + "SignatureCheck/" + MOA + "Code"; + /** Xpath expression to the XMLDSIGManifestCheckCode element */ + private static final String XMLDSIG_MANIFEST_CHECK_CODE_XPATH = + ROOT + MOA + "XMLDSIGManifestCheck/" + MOA + "Code"; + /** Xpath expression to the CertificateCheckCode element */ + private static final String CERTIFICATE_CHECK_CODE_XPATH = + ROOT + MOA + "CertificateCheck/" + MOA + "Code"; + + + /** This is the root element of the XML-Document provided by the Security Layer Card*/ + private Element verifyXMLSignatureResponse; + + /** + * Constructor for VerifyXMLSignatureResponseParser. + * A DOM-representation of the incoming String will be created + * @param xmlResponse <code><InfoboxReadResponse></code> as String + * @throws ParseException on any parsing error + */ + public VerifyXMLSignatureResponseParser(String xmlResponse) throws ParseException{ + try { + InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8")); + + verifyXMLSignatureResponse = DOMUtils.parseXmlValidating(s); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + } + + /** + * Constructor for VerifyXMLSignatureResponseParser. + * A DOM-representation of the incoming Inputstream will be created + * @param xmlResponse <code><InfoboxReadResponse></code> as InputStream + * @throws Exception on any parsing error + */ + public VerifyXMLSignatureResponseParser(InputStream xmlResponse) throws Exception + { + try { + verifyXMLSignatureResponse = DOMUtils.parseXmlValidating(xmlResponse); + } + catch (Throwable t) { + throw new ParseException("parser.01", null, t); + } + } + + /** + * Constructor for VerifyXMLSignatureResponseParser. + * The incoming Element will be used for further operations + * @param xmlResponse <code><InfoboxReadResponse></code> as Element + */ + public VerifyXMLSignatureResponseParser(Element xmlResponse) + { + verifyXMLSignatureResponse =xmlResponse; + + } + + /** + * Parse identity link from <code><InfoboxReadResponse></code> + * @return Identity link + * @throws ParseException on any parsing error + */ + + public VerifyXMLSignatureResponse parseData() throws ParseException { + + VerifyXMLSignatureResponse respData=new VerifyXMLSignatureResponse(); + + try { + respData.setXmlDsigSubjectName(XPathUtils.getElementValue(verifyXMLSignatureResponse,DSIG_SUBJECT_NAME_XPATH,"")); + Element e = (Element)XPathUtils.selectSingleNode(verifyXMLSignatureResponse,QUALIFIED_CERTIFICATE_XPATH); + respData.setQualifiedCertificate(e!=null); + + Base64InputStream in = new Base64InputStream(new ByteArrayInputStream(XPathUtils.getElementValue( + verifyXMLSignatureResponse,DSIG_X509_CERTIFICATE_XPATH,"").getBytes("UTF-8")),true); + + respData.setX509certificate(new X509Certificate(in)); + Element publicAuthority = (Element)XPathUtils.selectSingleNode(verifyXMLSignatureResponse,PUBLIC_AUTHORITY_XPATH); + respData.setPublicAuthority(publicAuthority != null); + respData.setPublicAuthorityCode(XPathUtils.getElementValue(verifyXMLSignatureResponse,PUBLIC_AUTHORITY_CODE_XPATH,"")); + respData.setSignatureCheckCode(new Integer(XPathUtils.getElementValue(verifyXMLSignatureResponse,SIGNATURE_CHECK_CODE_XPATH,"")).intValue()); + + String xmlDsigCheckCode = XPathUtils.getElementValue(verifyXMLSignatureResponse,XMLDSIG_MANIFEST_CHECK_CODE_XPATH,null); + if (xmlDsigCheckCode!=null) + { + respData.setXmlDSIGManigest(true); + respData.setXmlDSIGManifestCheckCode(new Integer(xmlDsigCheckCode).intValue()); + } + else + respData.setXmlDSIGManigest(false); + respData.setCertificateCheckCode(new Integer(XPathUtils.getElementValue(verifyXMLSignatureResponse,CERTIFICATE_CHECK_CODE_XPATH,"")).intValue()); + } + catch (Throwable t) { + throw new ParseException("parser.01", null, t); + } + return respData; + } + + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java new file mode 100644 index 000000000..96e8e6dd6 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java @@ -0,0 +1,202 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; + +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.WrongParametersException; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.URLDecoder; + +/** + * Base class for MOA-ID Auth Servlets, providing standard error handling + * and constant names. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthServlet extends HttpServlet implements MOAIDAuthConstants { + + + /** + * Handles an error. <br> + * <ul> + * <li>Logs the error</li> + * <li>Places error message and exception thrown into the request + * as request attributes (to be used by <code>"/errorpage-auth.jsp"</code>)</li> + * <li>Sets HTTP status 500 (internal server error)</li> + * </ul> + * + * @param errorMessage error message + * @param exceptionThrown exception thrown + * @param req servlet request + * @param resp servlet response + */ + protected void handleError( + String errorMessage, Throwable exceptionThrown, HttpServletRequest req, HttpServletResponse resp) { + + + if(null != errorMessage) { + Logger.error(errorMessage); + req.setAttribute("ErrorMessage", errorMessage ); + } + + if (null != exceptionThrown) { + if(null == errorMessage) errorMessage = exceptionThrown.getMessage(); + Logger.error(errorMessage, exceptionThrown); + req.setAttribute("ExceptionThrown", exceptionThrown); + } + + //forward this to errorpage-auth.jsp where the HTML error page is generated + ServletContext context = getServletContext(); + RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-auth.jsp"); + try { + dispatcher.forward(req, resp); + } catch (ServletException e) { + Logger.error(e); + } catch (IOException e) { + Logger.error(e); + } + + } + /** + * Handles a <code>WrongParametersException</code>. + * @param req servlet request + * @param resp servlet response + */ + protected void handleWrongParameters(WrongParametersException ex, HttpServletRequest req, HttpServletResponse resp) { + Logger.error(ex.toString()); + req.setAttribute("WrongParameters", ex.getMessage()); + + // forward this to errorpage-auth.jsp where the HTML error page is generated + ServletContext context = getServletContext(); + RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-auth.jsp"); + try { + dispatcher.forward(req, resp); + } catch (ServletException e) { + Logger.error(e); + } catch (IOException e) { + Logger.error(e); + } + } + + /** + * Logs all servlet parameters for debugging purposes. + */ + protected void logParameters(HttpServletRequest req) { + for (Enumeration params = req.getParameterNames(); params.hasMoreElements(); ) { + String parname = (String)params.nextElement(); + Logger.debug("Parameter " + parname + req.getParameter(parname)); + } + } + + /** + * Parses the request input stream for parameters, assuming parameters are encoded UTF-8 + * (no standard exists how browsers should encode them). + * + * @param req servlet request + * + * @return mapping parameter name -> value + * + * @throws IOException if parsing request parameters fails. + * + * @throws FileUploadException if parsing request parameters fails. + */ + protected Map getParameters(HttpServletRequest req) + throws IOException, FileUploadException { + + Map parameters = new HashMap(); + + + if (ServletFileUpload.isMultipartContent(req)) + { + // request is encoded as mulitpart/form-data + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = null; + upload = new ServletFileUpload(factory); + List items = null; + items = upload.parseRequest(req); + for (int i = 0; i < items.size(); i++) + { + FileItem item = (FileItem) items.get(i); + if (item.isFormField()) + { + // Process only form fields - no file upload items + parameters.put(item.getFieldName(), item.getString("UTF-8")); + Logger.debug("Processed multipart/form-data request parameter: \nName: " + + item.getFieldName() + "\nValue: " + + item.getString("UTF-8")); + } + } + } + + else + { + // request is encoded as application/x-www-urlencoded + InputStream in = req.getInputStream(); + + String paramName; + String paramValueURLEncoded; + do { + paramName = new String(readBytesUpTo(in, '=')); + if (paramName.length() > 0) { + paramValueURLEncoded = readBytesUpTo(in, '&'); + String paramValue = URLDecoder.decode(paramValueURLEncoded, "UTF-8"); + parameters.put(paramName, paramValue); + } + } + while (paramName.length() > 0); + in.close(); + } + + return parameters; + } + + /** + * Reads bytes up to a delimiter, consuming the delimiter. + * @param in input stream + * @param delimiter delimiter character + * @return String constructed from the read bytes + * @throws IOException + */ + protected String readBytesUpTo(InputStream in, char delimiter) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + boolean done = false; + int b; + while (! done && (b = in.read()) >= 0) { + if (b == delimiter) + done = true; + else + bout.write(b); + } + return bout.toString(); + } + + /** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ConfigurationServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ConfigurationServlet.java new file mode 100644 index 000000000..f33377547 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ConfigurationServlet.java @@ -0,0 +1,75 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.IOException; +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.auth.MOAIDAuthInitializer; +import at.gv.egovernment.moa.id.util.HTTPRequestJSPForwarder; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for updating the MOA-ID Auth configuration from configuration file + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class ConfigurationServlet extends HttpServlet { + + /** + * Handle a HTTP GET request, used to indicated that the MOA + * configuration needs to be updated (reloaded). + * + * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + MOAIDMessageProvider msg = MOAIDMessageProvider.getInstance(); + + try { + MOAIDAuthInitializer.initialized=false; + MOAIDAuthInitializer.initialize(); + String message = msg.getMessage("config.00", new Object[] + { DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.GERMAN).format(new Date())} ); + + Logger.info(message); + HTTPRequestJSPForwarder.forwardNamed(message, "/message-auth.jsp", getServletContext(), request, response); + + } catch (Throwable t) { + String errorMessage = msg.getMessage("config.04", null); + Logger.error(errorMessage, t); + HTTPRequestJSPForwarder.forwardNamed(errorMessage, "/message-auth.jsp", getServletContext(), request, response); + } + } + + /** + * Do the same as <code>doGet</code>. + * + * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest, HttpServletResponse) + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + doGet(request, response); + } + + /** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + } + +} + + diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetAuthenticationDataService.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetAuthenticationDataService.java new file mode 100644 index 000000000..c41b514c8 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetAuthenticationDataService.java @@ -0,0 +1,135 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.util.Calendar; + +import org.apache.axis.AxisFault; +import org.w3c.dom.Element; + +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.SAMLResponseBuilder; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.DateTimeUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Web service for picking up authentication data created in the MOA-ID Auth component. + * + * @author Paul Ivancsics + * @version $Id$ + * @see at.gv.egovernment.moa.id.auth.AuthenticationServer#getAuthenticationData + */ +public class GetAuthenticationDataService implements Constants { + + /** + * Constructor for GetAuthenticationDataService. + */ + public GetAuthenticationDataService() { + super(); + } + + /** + * Takes a <code>lt;samlp:Request></code> containing a + * <code>SAML artifact</code> and returns the corresponding + * authentication data <code>lt;saml:Assertion></code> + * (obtained from the <code>AuthenticationServer</code>), + * enclosed in a <code>lt;samlp:Response></code>. + * <br/>Bad requests are mapped into various <code>lt;samlp:StatusCode></code>s, + * possibly containing enclosed sub-<code>lt;samlp:StatusCode></code>s. + * The status codes are defined in the SAML specification. + * + * @param requests request elements of type <code>lt;samlp:Request></code>; + * only 1 request element is allowed + * @return response element of type <code>lt;samlp:Response></code>, + * packed into an <code>Element[]</code> + * @throws AxisFault thrown when an error occurs in assembling the + * <code>lt;samlp:Response></code> + */ + public Element[] Request(Element[] requests) + throws AxisFault { + + Element request = requests[0]; + Element[] responses = new Element[1]; + String requestID = ""; + String statusCode = ""; + String subStatusCode = null; + String statusMessageCode = null; + String statusMessage = null; + String samlAssertion = ""; + if (requests.length > 1) { + // more than 1 request given as parameter + statusCode = "samlp:Requester"; + subStatusCode = "samlp:TooManyResponses"; + statusMessageCode = "1201"; + } + else { + try { + DOMUtils.validateElement(request, ALL_SCHEMA_LOCATIONS, null); + NodeList samlArtifactList = XPathUtils.selectNodeList(request, "samlp:AssertionArtifact"); + if (samlArtifactList.getLength() == 0) { + // no SAML artifact given in request + statusCode = "samlp:Requester"; + statusMessageCode = "1202"; + } + else if (samlArtifactList.getLength() > 1) { + // too many SAML artifacts given in request + statusCode = "samlp:Requester"; + subStatusCode = "samlp:TooManyResponses"; + statusMessageCode = "1203"; + } + else { + Element samlArtifactElem = (Element)samlArtifactList.item(0); + requestID = samlArtifactElem.getAttribute("RequestID"); + String samlArtifact = DOMUtils.getText(samlArtifactElem); + try { + AuthenticationData authData = AuthenticationServer.getInstance(). + getAuthenticationData(samlArtifact); + // success + samlAssertion = authData.getSamlAssertion(); + statusCode = "samlp:Success"; + statusMessageCode = "1200"; + } + catch (AuthenticationException ex) { + // no authentication data for given SAML artifact + statusCode = "samlp:Requester"; + subStatusCode = "samlp:ResourceNotRecognized"; + statusMessage = ex.toString(); + } + } + } + catch (Throwable t) { + // invalid request format + statusCode = "samlp:Requester"; + statusMessageCode = "1204"; + } + } + try { + String responseID = Random.nextRandom(); + String issueInstant = DateTimeUtils.buildDateTime(Calendar.getInstance()); + if (statusMessage == null) + statusMessage = MOAIDMessageProvider.getInstance().getMessage(statusMessageCode, null); + responses[0] = new SAMLResponseBuilder().build( + responseID, requestID, issueInstant, statusCode, subStatusCode, statusMessage, samlAssertion); + } + catch (MOAIDException e) { + AxisFault fault = AxisFault.makeFault(e); + fault.setFaultDetail(new Element[] { e.toErrorResponse()}); + throw fault; + } + catch (Throwable t) { + MOAIDException e = new MOAIDException("1299", null, t); + AxisFault fault = AxisFault.makeFault(e); + fault.setFaultDetail(new Element[] { e.toErrorResponse()}); + throw fault; + } + return responses; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/SelectBKUServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/SelectBKUServlet.java new file mode 100644 index 000000000..4dc69c70b --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/SelectBKUServlet.java @@ -0,0 +1,99 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.MOAIDAuthInitializer; +import at.gv.egovernment.moa.id.auth.WrongParametersException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for selecting a BKU. + * <br>In case of {@link AuthConfigurationProvider#getBKUSelectionType}==HTMLComplete, + * the browser is redirected to the configured "BKU-Auswahl-URL". + * <br>In case of {@link AuthConfigurationProvider#getBKUSelectionType}==HTMLSelect, + * the list of available BKU's is fetched from a BKU-Auswahl server, and presented + * to the user in an HTML form. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SelectBKUServlet extends AuthServlet { + + /** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + try { + super.init(servletConfig); + MOAIDAuthInitializer.initialize(); + Logger.debug("default platform file.encoding: " + System.getProperty("file.encoding")); + Logger.info(MOAIDMessageProvider.getInstance().getMessage("init.00", null)); + } + catch (Exception ex) { + Logger.fatal(MOAIDMessageProvider.getInstance().getMessage("init.02", null), ex); + throw new ServletException(ex); + } + } + + /** + * Responds with an HTML form which requests the user to choose a BKU. + */ + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("GET SelectBKU"); + String authURL = + req.getScheme() + "://" + + req.getServerName() + ":" + + req.getServerPort() + + req.getContextPath() + "/"; + String target = req.getParameter(PARAM_TARGET); + String oaURL = req.getParameter(PARAM_OA); + String bkuSelectionTemplateURL = req.getParameter(PARAM_BKUTEMPLATE); + String templateURL = req.getParameter(PARAM_TEMPLATE); + resp.setHeader(HEADER_EXPIRES,HEADER_VALUE_EXPIRES); + resp.setHeader(HEADER_PRAGMA,HEADER_VALUE_PRAGMA); + resp.setHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL); + resp.addHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL_IE); + + try { + String returnValue = AuthenticationServer.getInstance().selectBKU( + authURL, target, oaURL, bkuSelectionTemplateURL, templateURL); + String bkuSelectionType = AuthConfigurationProvider.getInstance().getBKUSelectionType(); + if (bkuSelectionType.equals(AuthConfigurationProvider.BKU_SELECTION_TYPE_HTMLCOMPLETE)) { + // bkuSelectionType==HTMLComplete + String redirectURL = returnValue; + resp.setContentType("text/html"); + resp.sendRedirect(redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + } else { + // bkuSelectionType==HTMLSelect + String htmlForm = returnValue; + resp.setContentType("text/html;charset=UTF-8"); + Logger.debug("HTML-Form: " + htmlForm); + Writer out = new OutputStreamWriter(resp.getOutputStream(), "UTF8"); + out.write(htmlForm); + out.flush(); + Logger.debug("Finished GET SelectBKU"); + } + } + catch (WrongParametersException ex) { + handleWrongParameters(ex, req, resp); + } + catch (Throwable ex) { + handleError(null, ex, req, resp); + } + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java new file mode 100644 index 000000000..6098f5138 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java @@ -0,0 +1,103 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.MOAIDAuthInitializer; +import at.gv.egovernment.moa.id.auth.WrongParametersException; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for starting a MOA ID authentication session. + * Utilizes the {@link AuthenticationServer}. + * + * @author Paul Ivancsics + * @version $Id$ + * @see AuthenticationServer#startAuthentication + */ +public class StartAuthenticationServlet extends AuthServlet { + + /** + * Responds with an HTML form which upon submit requests the identity link + * from the security layer implementation. + * <br> + * Response: + * <ul> + * <li>Content type: <code>"text/html"</code></li> + * <li>Content: see return value of {@link AuthenticationServer#startAuthentication}</li> + * <li>Error status: <code>500</code> + * </ul> + * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) + */ + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("GET StartAuthentication"); + String authURL = + req.getScheme() + "://" + + req.getServerName() + ":" + + req.getServerPort() + + req.getContextPath() + "/"; + String target = req.getParameter(PARAM_TARGET); + String oaURL = req.getParameter(PARAM_OA); + String bkuURL = req.getParameter(PARAM_BKU); + String templateURL = req.getParameter(PARAM_TEMPLATE); + String sessionID = req.getParameter(PARAM_SESSIONID); + resp.setHeader(HEADER_EXPIRES,HEADER_VALUE_EXPIRES); + resp.setHeader(HEADER_PRAGMA,HEADER_VALUE_PRAGMA); + resp.setHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL); + resp.addHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL_IE); + try { + String getIdentityLinkForm = + AuthenticationServer.getInstance().startAuthentication(authURL, target, oaURL, templateURL, bkuURL, sessionID); + resp.setContentType("text/html;charset=UTF-8"); + PrintWriter out = new PrintWriter(resp.getOutputStream()); + out.print(getIdentityLinkForm); + out.flush(); + Logger.debug("Finished GET StartAuthentication"); + } + catch (WrongParametersException ex) { + handleWrongParameters(ex, req, resp); + } + catch (MOAIDException ex) { + handleError(null, ex, req, resp); + } + } + + + /** + * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + doGet(req, resp); + } + + + /** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + try { + super.init(servletConfig); + MOAIDAuthInitializer.initialize(); + Logger.info(MOAIDMessageProvider.getInstance().getMessage("init.00", null)); + } + catch (Exception ex) { + Logger.fatal(MOAIDMessageProvider.getInstance().getMessage("init.02", null), ex); + throw new ServletException(ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java new file mode 100644 index 000000000..6ec4a247d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java @@ -0,0 +1,120 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.IOException; +import at.gv.egovernment.moa.util.URLEncoder; //java.net.URLEncoder; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileUploadException; + +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for verifying the signed authentication block + * provided by the security layer implementation. + * Utilizes the {@link AuthenticationServer}. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class VerifyAuthenticationBlockServlet extends AuthServlet { + + + /** + * Constructor for VerifyAuthenticationBlockServlet. + */ + public VerifyAuthenticationBlockServlet() { + super(); + } + + /** + * GET requested by security layer implementation to verify + * that data URL resource is available. + * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) + */ + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("GET VerifyAuthenticationBlock"); + } + + /** + * Verifies the signed authentication block and redirects the browser + * to the online application requested, adding a parameter needed for + * retrieving the authentication data. + * <br> + * Request parameters: + * <ul> + * <li>MOASessionID: ID of associated authentication session</li> + * <li>XMLResponse: <code><CreateXMLSignatureResponse></code></li> + * </ul> + * Response: + * <ul> + * <li>Status: <code>302</code></li> + * <li>Header <code>"Location"</code>: URL of the online application requested, with + * parameters <code>"Target"</code>(only if the online application is + * a public service) and <code>"SAMLArtifact"</code> added</li> + * <li>Error status: <code>500</code> + * </ul> + * @see AuthenticationServer#verifyAuthenticationBlock + * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest, HttpServletResponse) + */ + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("POST VerifyAuthenticationBlock"); + Map parameters; + try + { + parameters = getParameters(req); + } catch (FileUploadException e) + { + Logger.error("Parsing mulitpart/form-data request parameters failed: " + e.getMessage()); + throw new IOException(e.getMessage()); + } + String sessionID = req.getParameter(PARAM_SESSIONID); + String createXMLSignatureResponse = (String)parameters.get(PARAM_XMLRESPONSE); + + try { + AuthenticationSession session = AuthenticationServer.getSession(sessionID); + String samlArtifactBase64 = + AuthenticationServer.getInstance().verifyAuthenticationBlock(sessionID, createXMLSignatureResponse); + String redirectURL = session.getOAURLRequested(); + if (!session.getBusinessService()) { + redirectURL = addURLParameter(redirectURL, PARAM_TARGET, URLEncoder.encode(session.getTarget(), "UTF-8")); + } + redirectURL = addURLParameter(redirectURL, PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8")); + redirectURL = resp.encodeRedirectURL(redirectURL); + resp.setContentType("text/html"); + resp.setStatus(302); + resp.addHeader("Location", redirectURL); + Logger.debug("REDIRECT TO: " + redirectURL); + } + + catch (MOAIDException ex) { + handleError(null, ex, req, resp); + } + + } + /** + * Adds a parameter to a URL. + * @param url the URL + * @param paramname parameter name + * @param paramvalue parameter value + * @return the URL with parameter added + */ + private static String addURLParameter(String url, String paramname, String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyIdentityLinkServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyIdentityLinkServlet.java new file mode 100644 index 000000000..2134c1444 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyIdentityLinkServlet.java @@ -0,0 +1,107 @@ +package at.gv.egovernment.moa.id.auth.servlet; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.FileUploadException; + +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for verifying the identity link + * provided by the security layer implementation. + * Utilizes the {@link AuthenticationServer}. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class VerifyIdentityLinkServlet extends AuthServlet { + + /** + * Constructor for VerifyIdentityLinkServlet. + */ + public VerifyIdentityLinkServlet() { + super(); + } + + /** + * GET requested by security layer implementation to verify + * that data URL resource is available. + * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) + */ + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("GET VerifyIdentityLink"); + } + + /** + * Verifies the identity link and responds with a new + * <code>CreateXMLSignatureRequest</code>. + * <br> + * Request parameters: + * <ul> + * <li>MOASessionID: ID of associated authentication session</li> + * <li>XMLResponse: <code><InfoboxReadResponse></code></li> + * </ul> + * Response: + * <ul> + * <li>Content type: <code>"text/xml"</code></li> + * <li>Content: see return value of {@link AuthenticationServer#verifyIdentityLink}</li> + * <li>Error status: <code>500</code> + * </ul> + * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest, HttpServletResponse) + */ + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + Logger.debug("POST VerifyIdentityLink"); + Map parameters; + try + { + parameters = getParameters(req); + } catch (FileUploadException e) + { + Logger.error("Parsing mulitpart/form-data request parameters failed: " + e.getMessage()); + throw new IOException(e.getMessage()); + } + String sessionID = req.getParameter(PARAM_SESSIONID); + + + try { + AuthenticationSession session = AuthenticationServer.getSession(sessionID); + + String createXMLSignatureRequest = + AuthenticationServer.getInstance().verifyIdentityLink(sessionID, parameters); + resp.setStatus(307); + String dataURL = new DataURLBuilder().buildDataURL( + session.getAuthURL(), AuthenticationServer.REQ_VERIFY_AUTH_BLOCK, sessionID); + resp.addHeader("Location", dataURL); + + //TODO test impact of explicit setting charset with older versions of BKUs (HotSign) + resp.setContentType("text/xml;charset=UTF-8"); + + OutputStream out = resp.getOutputStream(); + out.write(createXMLSignatureRequest.getBytes("UTF-8")); + out.flush(); + out.close(); + Logger.debug("Finished POST VerifyIdentityLink"); + } + catch (MOAIDException ex) { + handleError(null, ex, req, resp); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/CreateXMLSignatureResponseValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/CreateXMLSignatureResponseValidator.java new file mode 100644 index 000000000..e6c9f4bee --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/CreateXMLSignatureResponseValidator.java @@ -0,0 +1,274 @@ +package at.gv.egovernment.moa.id.auth.validator; + +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.data.SAMLAttribute; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.StringUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * + * This class is used to validate an {@link CreateXMLSignatureResponse} + * returned by the security layer. + * This class implements the Singleton pattern. + * @author Stefan Knirsch + * @version $Id$ + */ +public class CreateXMLSignatureResponseValidator { + + + /** Xpath expression to the dsig:Signature element */ + private static final String SIGNATURE_XPATH = Constants.DSIG_PREFIX + ":Signature"; + + + /** Singleton instance. <code>null</code>, if none has been created. */ + private static CreateXMLSignatureResponseValidator instance; + + /** + * Constructor for a singleton CreateXMLSignatureResponseValidator. + * @return an instance of CreateXMLSignatureResponseValidator + * @throws ValidateException if no instance can be created + */ + public static synchronized CreateXMLSignatureResponseValidator getInstance() + throws ValidateException { + if (instance == null) { + instance = new CreateXMLSignatureResponseValidator(); + } + return instance; + } + + + /** + * The Method validate is used for validating an explicit {@link CreateXMLSignatureResponse} + * @param createXMLSignatureResponse + * @param session + * @throws ValidateException + */ + public void validate(CreateXMLSignatureResponse createXMLSignatureResponse, AuthenticationSession session) + throws ValidateException { + + // A3.056: more then one /saml:Assertion/saml:AttributeStatement/saml:Subject/saml:NameIdentifier + + String gbTarget = session.getTarget(); + String oaURL = session.getPublicOAURLPrefix(); + boolean businessService = session.getBusinessService(); + + IdentityLink identityLink = session.getIdentityLink(); + + Element samlAssertion = createXMLSignatureResponse.getSamlAssertion(); + String issuer = samlAssertion.getAttribute("Issuer"); + if (issuer == null) { + // should not happen, because parser would dedect this + throw new ValidateException("validator.32", null); + } + String issueInstant = samlAssertion.getAttribute("IssueInstant"); + if (!issueInstant.equals(session.getIssueInstant())) { + throw new ValidateException("validator.39", new Object[] {issueInstant, session.getIssueInstant()}); + } + + String name = identityLink.getName(); + if (!issuer.equals(name)) { + throw new ValidateException("validator.33", new Object[] {issuer, name}); + } + + SAMLAttribute[] samlAttributes = createXMLSignatureResponse.getSamlAttributes(); + + boolean foundOA = false; + boolean foundGB = false; + boolean foundWBPK = false; + int offset = 0; + + // check number of SAML aatributes + List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); + int extendedSAMLAttributesNum = 0; + if (extendedSAMLAttributes != null) { + extendedSAMLAttributesNum = extendedSAMLAttributes.size(); + } + int expectedSAMLAttributeNumber = + AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES + extendedSAMLAttributesNum; + if (!session.getSAMLAttributeGebeORwbpk()) expectedSAMLAttributeNumber--; + int actualSAMLAttributeNumber = samlAttributes.length; + if (actualSAMLAttributeNumber != expectedSAMLAttributeNumber) { + Logger.error("Wrong number of SAML attributes in CreateXMLSignatureResponse: expected " + + expectedSAMLAttributeNumber + ", but was " + actualSAMLAttributeNumber); + throw new ValidateException( + "validator.36", + new Object[] {String.valueOf(actualSAMLAttributeNumber), String.valueOf(expectedSAMLAttributeNumber)}); + } + + SAMLAttribute samlAttribute; + if (session.getSAMLAttributeGebeORwbpk()) { + // check the first attribute ("Geschaeftsbereich" or "wbPK") + samlAttribute = samlAttributes[0]; + if (businessService) { + if (!samlAttribute.getName().equals("wbPK")) { + if (samlAttribute.getName().equals("Geschaeftsbereich")) { + throw new ValidateException("validator.26", null); + } else { + throw new ValidateException( + "validator.37", + new Object[] {samlAttribute.getName(), "wbPK", String.valueOf(1)}); + } + } + if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) { + foundWBPK = true; + try { + Element attrValue = (Element)samlAttribute.getValue(); + String value = ((Element)attrValue.getElementsByTagNameNS(Constants.PD_NS_URI, "Value").item(0)).getFirstChild().getNodeValue(); + String type = ((Element)attrValue.getElementsByTagNameNS(Constants.PD_NS_URI, "Type").item(0)).getFirstChild().getNodeValue(); + if (!value.equals(identityLink.getIdentificationValue())) { + throw new ValidateException("validator.28", null); + } + if (!type.equals(identityLink.getIdentificationType())) { + throw new ValidateException("validator.28", null); + } + } catch (Exception ex) { + throw new ValidateException("validator.29", null); + } + } else { + throw new ValidateException("validator.30", null); + } + } else { + if (!samlAttribute.getName().equals("Geschaeftsbereich")) { + if (samlAttribute.getName().equals("wbPK")) { + throw new ValidateException("validator.26", null); + } else { + throw new ValidateException( + "validator.37", + new Object[] {samlAttribute.getName(), "Geschaeftsbereich", String.valueOf(1)}); + } + } + if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) { + foundGB = true; + if (!gbTarget.equals((String)samlAttribute.getValue())) { + throw new ValidateException("validator.13", null); + } + } else { + throw new ValidateException("validator.12", null); + } + } + } else { + offset--; + } + + // check the second attribute (must be "OA") + samlAttribute = samlAttributes[1 + offset]; + if (!samlAttribute.getName().equals("OA")) { + throw new ValidateException( + "validator.37", + new Object[] {samlAttribute.getName(), "OA", String.valueOf(2)}); + } + if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) { + foundOA = true; + if (!oaURL.equals((String)samlAttribute.getValue())) { // CHECKS für die AttributeVALUES fehlen noch + throw new ValidateException("validator.16", new Object[] {":gefunden wurde '" + oaURL + "', erwartet wurde '" + samlAttribute.getValue()}); + } + } else { + throw new ValidateException("validator.15", null); + } + + // check the third attribute (must be "Geburtsdatum") + samlAttribute = samlAttributes[2 + offset]; + if (!samlAttribute.getName().equals("Geburtsdatum")) { + throw new ValidateException( + "validator.37", + new Object[] {samlAttribute.getName(), "Geburtsdatum", String.valueOf(3)}); + } + if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) { + String samlDateOfBirth = (String)samlAttribute.getValue(); + String dateOfBirth = identityLink.getDateOfBirth(); + if (!samlDateOfBirth.equals(dateOfBirth)) { + throw new ValidateException("validator.34", new Object[] {samlDateOfBirth, dateOfBirth}); + } + } else { + throw new ValidateException("validator.35", null); + } + + // now check the extended SAML attributes + int i = AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES + offset; + if (extendedSAMLAttributes != null) { + Iterator it = extendedSAMLAttributes.iterator(); + while (it.hasNext()) { + ExtendedSAMLAttribute extendedSAMLAttribute = (ExtendedSAMLAttribute)it.next(); + samlAttribute = samlAttributes[i]; + String actualName = samlAttribute.getName(); + String expectedName = extendedSAMLAttribute.getName(); + if (!actualName.equals(expectedName)) { + throw new ValidateException( + "validator.38", + new Object[] {"Name", String.valueOf((i+1)), actualName, actualName, expectedName }); + } + String actualNamespace = samlAttribute.getNamespace(); + String expectedNamespace = extendedSAMLAttribute.getNameSpace(); + if (!actualNamespace.equals(expectedNamespace)) { + throw new ValidateException( + "validator.38", + new Object[] {"Namespace", String.valueOf((i+1)), actualName, actualNamespace, expectedNamespace, }); + } + Object expectedValue = extendedSAMLAttribute.getValue(); + Object actualValue = samlAttribute.getValue(); + try { + if (expectedValue instanceof String) { + // replace \r\n because text might be base64-encoded + String expValue = StringUtils.replaceAll((String)expectedValue,"\r",""); + expValue = StringUtils.replaceAll(expValue,"\n",""); + String actValue = StringUtils.replaceAll((String)actualValue,"\r",""); + actValue = StringUtils.replaceAll(actValue,"\n",""); + if (!expValue.equals(actValue)) { + throw new ValidateException( + "validator.38", + new Object[] {"Wert", String.valueOf((i+1)), actualName, actualValue, expectedValue }); + } + } else if (expectedValue instanceof Element) { + // only check the name of the element + String actualElementName = ((Element)actualValue).getNodeName(); + String expectedElementName = ((Element)expectedValue).getNodeName(); + if (!(expectedElementName.equals(actualElementName))){ + throw new ValidateException( + "validator.38", + new Object[] {"Wert", String.valueOf((i+1)), actualName, actualElementName, expectedElementName}); + } + } else { + // should not happen + throw new ValidateException( + "validator.38", + new Object[] {"Typ", String.valueOf((i+1)), expectedName, "java.lang.String oder org.wrc.dom.Element", expectedValue.getClass().getName()}); + } + } catch (ClassCastException e) { + throw new ValidateException( + "validator.38", + new Object[] {"Typ", String.valueOf((i+1)), expectedName, expectedValue.getClass().getName(), actualValue.getClass().getName()}); + } + i++; + } + } + + + if (!foundOA) throw new ValidateException("validator.14", null); + if (businessService) { + if (session.getSAMLAttributeGebeORwbpk() && !foundWBPK) throw new ValidateException("validator.31", null); + } else { + if (!foundGB) throw new ValidateException("validator.11", null); + } + + //Check if dsig:Signature exists +// NodeList nl = createXMLSignatureResponse.getSamlAssertion().getElementsByTagNameNS(Constants.DSIG_NS_URI, "Signature"); +// if (nl.getLength() != 1) { +// throw new ValidateException("validator.05", null); +// } + Element dsigSignature = (Element) XPathUtils.selectSingleNode(samlAssertion, SIGNATURE_XPATH); + if (dsigSignature == null) { + throw new ValidateException("validator.05", new Object[] {"im AUTHBlock"}) ; + } + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/IdentityLinkValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/IdentityLinkValidator.java new file mode 100644 index 000000000..444f706e4 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/IdentityLinkValidator.java @@ -0,0 +1,159 @@ +package at.gv.egovernment.moa.id.auth.validator; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * This class is used to validate an {@link IdentityLink} + * returned by the security layer + * + * @author Stefan Knirsch + * @version $Id$ + */ +public class IdentityLinkValidator implements Constants { + + // + // XPath namespace prefix shortcuts + // + /** Xpath prefix for reaching PersonData Namespaces */ + private static final String PDATA = PD_PREFIX + ":"; + /** Xpath prefix for reaching SAML Namespaces */ + private static final String SAML = SAML_PREFIX + ":"; + /** Xpath prefix for reaching XML-DSIG Namespaces */ + private static final String DSIG = DSIG_PREFIX + ":"; + /** Xpath prefix for reaching ECDSA Namespaces */ + private static final String ECDSA = ECDSA_PREFIX + ":"; + /** Xpath expression to the root element */ + private static final String ROOT = ""; + /** Xpath expression to the SAML:SubjectConfirmationData element */ + private static final String SAML_SUBJECT_CONFIRMATION_DATA_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Subject/" + + SAML + + "SubjectConfirmation/" + + SAML + + "SubjectConfirmationData"; +/** Xpath expression to the PersonData:Person element */ + private static final String PERSON_XPATH = + SAML_SUBJECT_CONFIRMATION_DATA_XPATH + "/" + PDATA + "Person"; + /** Xpath expression to the SAML:Attribute element */ + private static final String ATTRIBUTE_XPATH = + ROOT + SAML + "AttributeStatement/" + SAML + "Attribute"; + /** Xpath expression to the SAML:AttributeName attribute */ + private static final String ATTRIBUTE_NAME_XPATH = + ROOT + SAML + "AttributeStatement/" + SAML + "Attribute/@AttributeName"; + /** Xpath expression to the SAML:AttributeNamespace attribute */ + private static final String ATTRIBUTE_NAMESPACE_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Attribute/@AttributeNamespace"; + /** Xpath expression to the SAML:AttributeValue element */ + private static final String ATTRIBUTE_VALUE_XPATH = + ROOT + + SAML + + "AttributeStatement/" + + SAML + + "Attribute/" + + SAML + + "AttributeValue"; + + /** Singleton instance. <code>null</code>, if none has been created. */ + private static IdentityLinkValidator instance; + + /** + * Constructor for a singleton IdentityLinkValidator. + * @return a new IdentityLinkValidator instance + * @throws ValidateException if no instance can be created + */ + public static synchronized IdentityLinkValidator getInstance() + throws ValidateException { + if (instance == null) { + instance = new IdentityLinkValidator(); + } + return instance; + } + + /** + * Method validate. Validates the {@link IdentityLink} + * @param identityLink The identityLink to validate + * @throws ValidateException on any validation error + */ + public void validate(IdentityLink identityLink) throws ValidateException { + + Element samlAssertion = identityLink.getSamlAssertion(); + //Search the SAML:ASSERTION Object (A2.054) + if (samlAssertion == null) { + throw new ValidateException("validator.00", null); + } + + // Check how many saml:Assertion/saml:AttributeStatement/ + // saml:Subject/ saml:SubjectConfirmation/ + // saml:SubjectConfirmationData/pr:Person of type + // PhysicalPersonType exist (A2.056) + NodeList nl = XPathUtils.selectNodeList(samlAssertion, PERSON_XPATH); + // If we have just one Person-Element we don't need to check the attributes + int counterPhysicalPersonType = 0; + if (nl.getLength() > 1) + for (int i = 0; i < nl.getLength(); i++) { + String xsiType = + ((Element) nl.item(i)) + .getAttributeNodeNS( + "http://www.w3.org/2001/XMLSchema-instance", + "type") + .getNodeValue(); + // We have to check if xsiType contains "PhysicalPersonType" + // An equal-check will fail because of the Namespace-prefix of the attribute value + if (xsiType.indexOf("PhysicalPersonType") > -1) + counterPhysicalPersonType++; + } + if (counterPhysicalPersonType > 1) + throw new ValidateException("validator.01", null); + + //Check the SAML:ATTRIBUTES + nl = XPathUtils.selectNodeList(samlAssertion, ATTRIBUTE_XPATH); + for (int i = 0; i < nl.getLength(); i++) { + String attributeName = + XPathUtils.getAttributeValue( + (Element) nl.item(i), + "@AttributeName", + null); + String attributeNS = + XPathUtils.getAttributeValue( + (Element) nl.item(i), + "@AttributeNamespace", + null); + if (attributeName.equals("CitizenPublicKey")) { + + if (attributeNS.equals("http://www.buergerkarte.at/namespaces/personenbindung/20020506#") || + attributeNS.equals("urn:publicid:gv.at:namespaces:identitylink:1.2")) { + Element attributeValue = + (Element) XPathUtils.selectSingleNode((Element) nl.item(i),nSMap, SAML + "AttributeValue/" + DSIG + "RSAKeyValue"); + if (attributeValue==null) + attributeValue = + (Element) XPathUtils.selectSingleNode((Element)nl.item(i), nSMap, SAML + "AttributeValue/" + ECDSA + "ECDSAKeyValue"); + if (attributeValue == null) + throw new ValidateException("validator.02", null); + + } + else + throw new ValidateException("validator.03", new Object [] {attributeNS} ); + } + else + throw new ValidateException("validator.04", new Object [] {attributeName} ); + } + + //Check if dsig:Signature exists + Element dsigSignature = (Element) XPathUtils.selectSingleNode(samlAssertion,ROOT + DSIG + "Signature"); + if (dsigSignature==null) throw new ValidateException("validator.05", new Object[] {"in der Personenbindung"}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/InfoboxValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/InfoboxValidator.java new file mode 100644 index 000000000..c776418ab --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/InfoboxValidator.java @@ -0,0 +1,32 @@ +package at.gv.egovernment.moa.id.auth.validator; + +import at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult; +import at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams; + +/** + * Validates an InfoboxReadResponse. + * An implementing class has to validate the content of the InfoboxReadResponse + * according to the type specific rules and guidelines of the underlying + * application. + */ +public interface InfoboxValidator { + + /** + * This method validates an InfoboxReadResponse. + * The method validates the content of the passed <code>infoboxReadResponse</code> + * according to the type specific rules and guidelines of the underlying + * application. + * + * @param params {@link at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams + * Parameters} needed by the validator. + * + * @return <code>True</code> if validation succeeds, + * otherwise <code>false</code>. + * + * @throws ValidateException If an error occurs on validating the + * InfoboxReadResponse. + */ + public InfoboxValidationResult validate (InfoboxValidatorParams params) + throws ValidateException; + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/ValidateException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/ValidateException.java new file mode 100644 index 000000000..a6685fca8 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/ValidateException.java @@ -0,0 +1,35 @@ +package at.gv.egovernment.moa.id.auth.validator; + +import at.gv.egovernment.moa.id.MOAIDException; + +/** + * Exception thrown while validating an incoming XML structure + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class ValidateException extends MOAIDException { + + /** + * Constructor for ValidateException. + * @param messageId + * @param parameters + */ + public ValidateException(String messageId, Object[] parameters) { + super(messageId, parameters); + } + + /** + * Constructor for ValidateException. + * @param messageId + * @param parameters + * @param wrapped + */ + public ValidateException( + String messageId, + Object[] parameters, + Throwable wrapped) { + super(messageId, parameters, wrapped); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java new file mode 100644 index 000000000..1f2ebc37c --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java @@ -0,0 +1,177 @@ +package at.gv.egovernment.moa.id.auth.validator; + +import iaik.asn1.structures.Name; +import iaik.security.ecc.ecdsa.ECPublicKey; +import iaik.utils.RFC2253NameParserException; +import iaik.x509.X509Certificate; +import iaik.x509.X509ExtensionInitException; + +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.List; + +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * This class is used to validate an {@link VerifyXMLSignatureResponse} + * returned by MOA-SPSS + * + * @author Stefan Knirsch + * @version $Id$ + */ +public class VerifyXMLSignatureResponseValidator { + + /** Identification string for checking identity link */ + public static final String CHECK_IDENTITY_LINK = "IdentityLink"; + /** Identification string for checking authentication block */ + public static final String CHECK_AUTH_BLOCK = "AuthBlock"; + + /** Singleton instance. <code>null</code>, if none has been created. */ + private static VerifyXMLSignatureResponseValidator instance; + + /** + * Constructor for a singleton VerifyXMLSignatureResponseValidator. + */ + public static synchronized VerifyXMLSignatureResponseValidator getInstance() + throws ValidateException { + if (instance == null) { + instance = new VerifyXMLSignatureResponseValidator(); + } + return instance; + } + + /** + * Validates a {@link VerifyXMLSignatureResponse} returned by MOA-SPSS. + * + * @param verifyXMLSignatureResponse the <code><VerifyXMLSignatureResponse></code> + * @param identityLinkSignersSubjectDNNames subject names configured + * @param whatToCheck is used to identify whether the identityLink or the Auth-Block is validated + * @param ignoreManifestValidationResult specifies whether the validation result of the + * manifest has to be ignored (identityLink validation if + * the OA is a business service) or not + * @throws ValidateException on any validation error + */ + public void validate(VerifyXMLSignatureResponse verifyXMLSignatureResponse, + List identityLinkSignersSubjectDNNames, + String whatToCheck, + boolean ignoreManifestValidationResult) + throws ValidateException { + + if (verifyXMLSignatureResponse.getSignatureCheckCode() != 0) + throw new ValidateException("validator.06", null); + + if (verifyXMLSignatureResponse.getCertificateCheckCode() != 0) { + String checkFailedReason =""; + if (verifyXMLSignatureResponse.getCertificateCheckCode() == 1) + checkFailedReason = MOAIDMessageProvider.getInstance().getMessage("validator.21", null); + if (verifyXMLSignatureResponse.getCertificateCheckCode() == 2) + checkFailedReason = MOAIDMessageProvider.getInstance().getMessage("validator.22", null); + if (verifyXMLSignatureResponse.getCertificateCheckCode() == 3) + checkFailedReason = MOAIDMessageProvider.getInstance().getMessage("validator.23", null); + if (verifyXMLSignatureResponse.getCertificateCheckCode() == 4) + checkFailedReason = MOAIDMessageProvider.getInstance().getMessage("validator.24", null); + if (verifyXMLSignatureResponse.getCertificateCheckCode() == 5) + checkFailedReason = MOAIDMessageProvider.getInstance().getMessage("validator.25", null); + + if (whatToCheck.equals(CHECK_IDENTITY_LINK)) + throw new ValidateException("validator.07", new Object[] { checkFailedReason } ); + else + throw new ValidateException("validator.19", new Object[] { checkFailedReason } ); + } + + if (ignoreManifestValidationResult) { + Logger.debug("OA type is business service, thus ignoring DSIG manifest validation result"); + } else { + if (verifyXMLSignatureResponse.isXmlDSIGManigest()) + if (verifyXMLSignatureResponse.getXmlDSIGManifestCheckCode() != 0) + throw new ValidateException("validator.08", null); + } + + + // TODO See Bug #322 + // Check result of SignatureManifestCheck + + + //Check whether the returned X509 SubjectName is in the MOA-ID configuration or not + if (identityLinkSignersSubjectDNNames != null) { + String subjectDN = ""; + X509Certificate x509Cert = verifyXMLSignatureResponse.getX509certificate(); + try { + subjectDN = ((Name) x509Cert.getSubjectDN()).getRFC2253String(); + } + catch (RFC2253NameParserException e) { + throw new ValidateException("validator.17", null); + } + // check the authorisation to sign the identity link + if (!identityLinkSignersSubjectDNNames.contains(subjectDN)) { + // subject DN check failed, try OID check: + try { + if (x509Cert.getExtension(MOAIDAuthConstants.IDENTITY_LINK_SIGNER_OID) == null) { + throw new ValidateException("validator.18", new Object[] { subjectDN }); + } else { + Logger.debug("Identity link signer cert accepted for signing identity link: " + + "subjectDN check failed, but OID check successfully passed."); + } + } catch (X509ExtensionInitException e) { + throw new ValidateException("validator.49", null); + } + } else { + Logger.debug("Identity link signer cert accepted for signing identity link: " + + "subjectDN check successfully passed."); + } + + } + } + + /** + * Method validateCertificate. + * @param verifyXMLSignatureResponse The VerifyXMLSignatureResponse + * @param idl The Identitylink + * @throws ValidateException + */ + public void validateCertificate( + VerifyXMLSignatureResponse verifyXMLSignatureResponse, + IdentityLink idl) + throws ValidateException { + + X509Certificate x509Response = verifyXMLSignatureResponse.getX509certificate(); + PublicKey[] pubKeysIdentityLink = (PublicKey[]) idl.getPublicKey(); + + PublicKey pubKeySignature = x509Response.getPublicKey(); + + boolean found = false; + for (int i = 0; i < pubKeysIdentityLink.length; i++) { + + //compare RSAPublicKeys + if ((idl.getPublicKey()[i] instanceof java.security.interfaces.RSAPublicKey) && + (pubKeySignature instanceof java.security.interfaces.RSAPublicKey)) { + + RSAPublicKey rsaPubKeySignature = (RSAPublicKey) pubKeySignature; + RSAPublicKey rsakey = (RSAPublicKey) pubKeysIdentityLink[i]; + + if (rsakey.getModulus().equals(rsaPubKeySignature.getModulus()) + && rsakey.getPublicExponent().equals(rsaPubKeySignature.getPublicExponent())) + found = true; + } + + //compare ECDSAPublicKeys + if((idl.getPublicKey()[i] instanceof iaik.security.ecc.ecdsa.ECPublicKey) && + (pubKeySignature instanceof iaik.security.ecc.ecdsa.ECPublicKey)) { + + ECPublicKey ecdsaPubKeySignature = (ECPublicKey) pubKeySignature; + ECPublicKey ecdsakey = (ECPublicKey) pubKeysIdentityLink[i]; + + if(ecdsakey.equals(ecdsaPubKeySignature)) + found = true; + } + } + + if (!found) + throw new ValidateException("validator.09", null); + } + +} |