package at.gv.egovernment.moa.id.proxy; import iaik.security.provider.IAIK; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import javax.crypto.Cipher; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import java.security.InvalidAlgorithmParameterException; import java.security.Key; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Security; import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; import at.gv.egovernment.moa.id.data.AuthenticationData; import at.gv.egovernment.moa.logging.Logger; 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.FileUtils; import at.gv.egovernment.moa.util.URLEncoder; import at.gv.egovernment.moa.id.config.ConfigurationProvider; import java.io.IOException; import java.util.*; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.*; import org.xml.sax.SAXException; /** * XMLLoginParameterResolver an implementation of implementation of interface * LoginParameterResolver * This implementation used to map identities stored in an XML file to parameters * which are given to OAs. * * @author Rudolf Schamberger * @version $Id$ */ public class XMLLoginParameterResolverEncryptedData implements LoginParameterResolver { //file which is parsed and interpreted for paremeter resolving. private String identityFile; private Cipher blowfishCipher; private Key key; /** * inner class used to store mapped parameters */ class LPRParams { /** * getter method for parameter Enabled. * Parameter Enabled decides if mapped parameters should be used by XMLLoginParameterResolver */ public boolean getEnabled() { return enabled.booleanValue(); } /** * getter method for parameter UN (username) * @return Parameter UN or null not set. */ public String getUN() { return UN; } /** * getter method for parameter UN (username) * @return Parameter UN or null not set. */ //TODO XMLLPR decrypt public String getPlainUN() { //Security.addProvider(); return UN; } /** * getter method for parameter PW (password) * @return Parameter PW or null not set. */ public String getPW() { return PW; } /** * getter method for generic parameter Param1 * @return Parameter Param1 or null not set. */ public String getParam1() { return Param1; } /** * getter method for generic parameter Param2 * @return Parameter Param2 or null not set. */ public String getParam2() { return Param2; } /** * getter method for generic parameter Param3 * @return Parameter Param3 or null not set. */ public String getParam3() { return Param3; } /** * Returns a string representation of LPRParams * * @return a String representation of this object. * @see XMLLoginParameterResolver.LPRParams */ public String toString() { return "Enabled: " + enabled.toString() + "UN: '" + UN + "' PW: '" + PW + "' Param1: '" + Param1 + "' Param2: '" + Param2 + "' Param3: '" + Param3 + "'\n"; } //private member variables used to store the parameters private Boolean enabled = null; private String UN = null; private String PW = null; private String Param1 = null; private String Param2 = null; private String Param3 = null; /** * Constructs a newly allocated XMLLoginParameterResolver.LPRParams object. * * @param enabled enable user mapping to parameter set for the parameter set. * @param UN username used in HTTP 401 - BasicAuthentication * @param PW password used in HTTP 401 - BasicAuthentication * @param Param1 generic parameter1 used in HeaderAuthentication and ParameterAuthentication * @param Param2 generic parameter2 used in HeaderAuthentication and ParameterAuthentication * @param Param3 generic parameter3 used in HeaderAuthentication and ParameterAuthentication **/ LPRParams(boolean enabled, String UN, String PW, String Param1, String Param2, String Param3) { this.enabled = new Boolean(enabled); this.UN = UN; this.PW = PW; this.Param1 = Param1; this.Param1 = Param2; this.Param1 = Param3; } /** * Constructs a newly allocated XMLLoginParameterResolver.LPRParams object. * * @param enabled enable user mapping to parameter set for the parameter set. * @param UN username used in HTTP 401 - BasicAuthentication * @param PW password used in HTTP 401 - BasicAuthentication **/ LPRParams(boolean enabled, String UN, String PW) { this(enabled, UN, PW, null, null, null); } } /** * Constructs a newly allocated XMLLoginParameterResolver object. **/ public XMLLoginParameterResolverEncryptedData() { bPKMap = new HashMap(); namedMap = new HashMap(); } /** * configuration method * @param configuration enabled enable user mapping to parameter set for the parameter set. */ public void configure(String configuration) throws LoginParameterResolverException { File idFile; Element rootElement; Security.addProvider(new IAIK()); try { blowfishCipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding", "IAIK"); } catch (NoSuchPaddingException e) { throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: NoSuchPaddingException \n" + e.toString()}); } catch (NoSuchProviderException e) { throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: NoSuchProviderException \n" + e.toString()}); } catch (NoSuchAlgorithmException e) { throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: NoSuchAlgorithmException \n" + e.toString()}); } String plaintext = "start"; String encrypted = encryptData(plaintext, "1234567890123456", "123hochgeheim"); String decrypted = decryptData(encrypted, "1234567890123456", "123hochgeheim"); Logger.debug("plaintext: " + plaintext); Logger.debug("encrypted: " + encrypted); Logger.debug("decrypted: " + decrypted); //make file name absolut (if it is relative to main config file) //TODO MOAID XMLLPR check String moaIDConfigFileName = System.getProperty(ConfigurationProvider.CONFIG_PROPERTY_NAME); String rootConfigFileDir = new File(moaIDConfigFileName).getParent(); this.identityFile = FileUtils.makeAbsoluteURL(configuration, rootConfigFileDir); if (null == identityFile || false == (idFile = new File(identityFile)).canRead()) { throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: could not read '" + identityFile + "' " }); } try { rootElement = readXMLFile(identityFile); } catch (IOException lex) { Logger.error(lex.toString()); throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: could not read '" + identityFile + "' " }); } catch (SAXException sex) { Logger.error(sex.toString()); throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: parsing problem in file:'" + identityFile + "' ", sex.toString() }); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block Logger.error(e.toString()); throw new LoginParameterResolverException("config.11", new Object[] { "XMLLoginParameterResolver: parsing problem in file:'" + identityFile + "' ", e.toString() }); } buildInfo(rootElement); isConfigured = true; } /** * encryptData method uses parameters masterSecret and bPK as key information to encrypt plaintext * @param plaintext * @param bPK * @param masterSecret * @returns encrypted data (blowfish encrypted, base64 encoded) * @throws LoginParameterResolverException */ public String encryptData(String plaintext, String bPK, String masterSecret) throws LoginParameterResolverException { try { String keyString = bPK + masterSecret; key = new iaik.security.cipher.SecretKey(keyString.getBytes("UTF-8"), "Blowfish"); IvParameterSpec param = new IvParameterSpec(new byte [] {0,0,0,0,0,0,0,0}); blowfishCipher.init(Cipher.ENCRYPT_MODE, key, param); byte [] cipherText = blowfishCipher.doFinal(plaintext.getBytes("UTF-8")); return Base64Utils.encode(cipherText); } catch (UnsupportedEncodingException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (InvalidKeyException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (BadPaddingException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IllegalBlockSizeException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IllegalStateException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (InvalidAlgorithmParameterException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IOException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } } /** * encryptData method uses parameters masterSecret and bPK as key information to decrypt ciphertext * @param ciphertext (blowfish encrypted, base64encoded) * @param bPK * @param masterSecret * @returns decrypted Data (plaintext) * @throws LoginParameterResolverException */ public String decryptData(String ciphertext, String bPK, String masterSecret) throws LoginParameterResolverException { try { String keyString = bPK + masterSecret; key = new iaik.security.cipher.SecretKey(keyString.getBytes("UTF-8"), "Blowfish"); IvParameterSpec param = new IvParameterSpec(new byte [] {0,0,0,0,0,0,0,0}); blowfishCipher.init(Cipher.DECRYPT_MODE, key, param); byte [] plaintext = blowfishCipher.doFinal(Base64Utils.decode(ciphertext, true)); return new String(plaintext); } catch (UnsupportedEncodingException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (InvalidKeyException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (BadPaddingException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IllegalBlockSizeException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IllegalStateException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (InvalidAlgorithmParameterException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } catch (IOException e) { throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); } } /** * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationHeaders(at.gv.egovernment.moa.id.config.proxy.OAConfiguration, at.gv.egovernment.moa.id.auth.data.AuthenticationData, java.lang.String) */ public Map getAuthenticationHeaders( OAConfiguration oaConf, AuthenticationData authData, String clientIPAddress) throws LoginParameterResolverException, NotAllowedException { Map result = new HashMap(); if (!isConfigured) { //TODO XMLLPR throw new LoginParameterResolverException("XMLLoginParameterResolver with configuration '" + identityFile + "' is not configured!", null); } //get the Identity of the user String famName = resolveValue("MOAFamilyName", authData, clientIPAddress); String givenName = resolveValue("MOAGivenName", authData, clientIPAddress); String dateOfBirth = resolveValue("MOADateOfBirth", authData, clientIPAddress); String bPK = resolveValue("MOABPK", authData, clientIPAddress); String userid = ""; String password = ""; LPRParams params = null; boolean userFound = false; //try bPK and named search params = bPKIdentitySearch(bPK); if (null == params) params = namedIdentitySearch(famName, givenName, dateOfBirth); //if both searches failed, report error. if(null == params) throw new NotAllowedException("User:_bPK:'" +bPK+ ", " + famName + ", " + givenName + "' not authorized.", null); //HTTP 401 - Basic Authentication if (oaConf.getAuthType().equals("basic")) { userid = (null != params.getUN()) ? params.getUN() : ""; password = (null != params.getPW()) ? params.getPW() : ""; try { String userIDPassword = userid + ":" + password; String credentials = Base64Utils.encode(userIDPassword.getBytes("UTF-8")); Logger.debug("XMLLoginParameterResolver: calculated credentials: " + credentials); result.put("Authorization", "Basic " + credentials); } catch (IOException ignore) { throw new LoginParameterResolverException("config.14", new Object[] {"internal error while encoding in Base64"}); } } else if (oaConf.getAuthType().equals("header")) { //HTTP Authentication String key; String resolvedValue; //TODO MOAID XMLLoginParameterResolver select value through OA-ConfigFile; if(null != params.getUN()) result.put("UN", params.getUN()); if(null != params.getPW()) result.put("UN", params.getPW()); if(null != params.getParam1()) result.put("UN", params.getParam1()); if(null != params.getParam2()) result.put("UN", params.getParam2()); if(null != params.getParam3()) result.put("UN", params.getParam3()); } else { throw new LoginParameterResolverException("config.14", new Object[] {"AuthType not supported"}); } return result; } /** * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationParameters(at.gv.egovernment.moa.id.config.proxy.OAConfiguration, at.gv.egovernment.moa.id.auth.data.AuthenticationData, java.lang.String) */ public Map getAuthenticationParameters( OAConfiguration oaConf, AuthenticationData authData, String clientIPAddress) throws LoginParameterResolverException, NotAllowedException { Map result = new HashMap(); if (!isConfigured) { Logger.warn("XMLLoginParameterResolver with configuration '" + identityFile + " is not configured"); return result; } String famName = resolveValue("MOAFamilyName", authData, clientIPAddress); String givenName = resolveValue("MOAGivenName", authData, clientIPAddress); String dateOfBirth = resolveValue("MOADateOfBirth", authData, clientIPAddress); String bPK = resolveValue("MOABPK", authData, clientIPAddress); String userid = ""; String password = ""; LPRParams params = null; //try bPK and named search params = bPKIdentitySearch(bPK); if (null == params) params = namedIdentitySearch(famName, givenName, dateOfBirth); //if both searches failed, report error. if(null == params) throw new NotAllowedException("User:_bPK:'" +bPK+ ", " + famName + ", " + givenName + "' not authorized.", null); //TODO MOAID XMLLoginParameterResolver URLEncoder.encode if (oaConf.getAuthType().equals("param")) { try { if(null != params.getUN()) result.put(XSD_UNATTR, URLEncoder.encode(params.getUN(),"ISO-8859-1")); if(null != params.getPW()) result.put(XSD_PWATTR, URLEncoder.encode(params.getPW(),"ISO-8859-1")); if(null != params.getParam1()) result.put(XSD_PARAM1ATTR, URLEncoder.encode(params.getParam1(),"ISO-8859-1")); if(null != params.getParam2()) result.put(XSD_PARAM2ATTR, URLEncoder.encode(params.getParam2(),"ISO-8859-1")); if(null != params.getParam3()) result.put(XSD_PARAM3ATTR, URLEncoder.encode(params.getParam3(),"ISO-8859-1")); } catch (UnsupportedEncodingException e) { // ISO-8859-1 is supported throw new LoginParameterResolverException("URLEncoder error", null); } } else { throw new LoginParameterResolverException("AuthType not supported", null); } return result; } /** * Resolves a login header or parameter value. * @param predicate header or parameter predicate name from online application configuration * @param authData authentication data for current login * @param clientIPAddress client IP address * @return header or parameter value resolved; null if unknown name is given */ private static String resolveValue( String predicate, AuthenticationData authData, String clientIPAddress) { if (predicate.equals("MOAGivenName")) return authData.getGivenName(); if (predicate.equals("MOAFamilyName")) return authData.getFamilyName(); if (predicate.equals("MOADateOfBirth")) return authData.getDateOfBirth(); if (predicate.equals("MOABPK")) return authData.getPBK(); if (predicate.equals("MOAPublicAuthority")) if (authData.isPublicAuthority()) return "true"; else return "false"; if (predicate.equals("MOABKZ")) return authData.getPublicAuthorityCode(); if (predicate.equals("MOAQualifiedCertificate")) if (authData.isQualifiedCertificate()) return "true"; else return "false"; if (predicate.equals("MOAStammzahl")) return authData.getIdentificationValue(); if (predicate.equals(MOAIdentificationValueType)) return authData.getIdentificationType(); if (predicate.equals("MOAIPAddress")) return clientIPAddress; else return null; } /** * reads, parses the configuration file of XMLLoginParameterResolver and returns the document element. * @param fileName of the configuration file. */ private Element readXMLFile(String fileName) throws ParserConfigurationException, SAXException, IOException { Logger.info("XMLLoginParameterResolver: Loading and parsing XMLPLoginParameterConfiguration configuration: " + fileName); InputStream stream = null; Element configElem; stream = new BufferedInputStream(new FileInputStream(fileName)); configElem = DOMUtils.parseDocument(stream, true, Constants.ALL_SCHEMA_LOCATIONS, null).getDocumentElement(); return configElem; } /** * buildInfo builds up the internal data mapping between the "Identities" and the "Parameters" from the parsed XML file. * @param root document root element. */ private void buildInfo(Element root) { NodeList idList = root.getElementsByTagName(XSD_IDELEM); NodeList paramList = root.getElementsByTagName(XSD_PARAMELEM); for (int i = 0; i < idList.getLength(); i++) Logger.debug("XMLLoginParameterResolver: LocalName idList: " + idList.item(i).getLocalName()); for (int i = 0; i < paramList.getLength(); i++) Logger.debug("XMLLoginParameterResolver: LocalName paramList: " + paramList.item(i).getLocalName()); for (int i = 0; i < idList.getLength(); i++) { Element tmpElem = (Element) idList.item(i); NodeList tmpList = tmpElem.getElementsByTagName(XSD_NAMEDIDELEM); for (int j = 0; j < tmpList.getLength(); j++) Logger.debug("XMLLoginParameterResolver: LocalName tmp: " + tmpList.item(j).getLocalName()); //Search for NamedIdentity Elements if (1 == tmpList.getLength()) { tmpElem = (Element) tmpList.item(0); String tmpStr = tmpElem.getAttribute(XSD_SURNAMEATTR) + "," + tmpElem.getAttribute(XSD_GIVENNAMEATTR) + "," + tmpElem.getAttribute(XSD_BIRTHDATEATTR); boolean tmpBool = false; if (tmpElem.getFirstChild() != null && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) tmpBool = true; //TODO XMLLPR remove Logger.debug("XMLLoginParameterResolver: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); tmpElem = (Element) paramList.item(i); Logger.debug("XMLLoginParameterResolver: attribute UN: " + tmpElem.getAttribute(XSD_UNATTR) + " attribute PW: " + tmpElem.getAttribute(XSD_PWATTR) + " attribute Param1: " + tmpElem.getAttribute(XSD_PARAM1ATTR) + " attribute Param2: " + tmpElem.getAttribute(XSD_PARAM2ATTR) + " attribute Param3: " + tmpElem.getAttribute(XSD_PARAM3ATTR) ); namedMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute(XSD_UNATTR), tmpElem.getAttribute(XSD_PWATTR), tmpElem.getAttribute(XSD_PARAM1ATTR), tmpElem.getAttribute(XSD_PARAM2ATTR), tmpElem.getAttribute(XSD_PARAM3ATTR)) ); } else { //bPKIdentity Elements tmpList = tmpElem.getElementsByTagName(XSD_BPKIDELEM); if (1 == tmpList.getLength()) { tmpElem = (Element) tmpList.item(0); String tmpStr = tmpElem.getAttribute(XSD_BPKATTR); boolean tmpBool = false; if (tmpElem.getFirstChild() != null && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) tmpBool = true; Logger.debug("XMLLoginParameterResolver: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); tmpElem = (Element) paramList.item(i); Logger.debug("XMLLoginParameterResolver: attribute UN: " + tmpElem.getAttribute(XSD_UNATTR) + " attribute PW: " + tmpElem.getAttribute(XSD_PWATTR) + " attribute Param1: " + tmpElem.getAttribute(XSD_PARAM1ATTR) + " attribute Param2: " + tmpElem.getAttribute(XSD_PARAM2ATTR) + " attribute Param3: " + tmpElem.getAttribute(XSD_PARAM3ATTR) ); namedMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute(XSD_UNATTR), tmpElem.getAttribute(XSD_PWATTR), tmpElem.getAttribute(XSD_PARAM1ATTR), tmpElem.getAttribute(XSD_PARAM2ATTR), tmpElem.getAttribute(XSD_PARAM3ATTR)) ); } else { Logger.warn( "XMLLoginParameterResolver: wrong format no Elements " + XSD_NAMEDIDELEM + " or " + XSD_BPKIDELEM + " found"); } } } Logger.debug("namedMap:" + namedMap.toString()); Logger.debug("bPKMap:" + bPKMap.toString()); } /** * searches for a given bPK and returns the appropriate LPRParams structure * @param bPK search argument * @returns LPRParams if bPK could be found in internal mappings or null otherwise. */ LPRParams bPKIdentitySearch(String bPK) { //search for mapping with bPK of the user Logger.info("XMLLoginParameterResolver: search for login data mapped to bPK:" + bPK); LPRParams params = (LPRParams) bPKMap.get(bPK); if (null == params) { Logger.info("XMLLoginParameterResolver: params for bPK: " + bPK + " not found!"); return null; } else if (params.getEnabled()) { Logger.info("XMLLoginParameterResolver: bPK: " + bPK + "found in list; user is enabled"); Logger.debug("XMLLoginParameterResolver: using: " + params.toString()); return params; } Logger.info("XMLLoginParameterResolver: bPK: " + bPK + "found in list but user is NOT enabled"); return null; } /** * searches for a given namedIdentity and returns the appropriate LPRParams structure * @param surName surname search argument * @param givenName givenname search argument * @param dateOfBirth dateofbirth search argument * @returns LPRParams if bPK could be found in internal mappings or null otherwise. */ LPRParams namedIdentitySearch(String surName, String givenName, String dateOfBirth) { Logger.info("XMLLoginParameterResolver: search for login data for SurName:" + surName + " GivenName: " + givenName + " DateOfBirth" + dateOfBirth); //try first a search with surname, givenname and birthdate LPRParams params = (LPRParams) namedMap.get(surName + "," + givenName + "," + dateOfBirth); if (null == params) { Logger.debug("XMLLoginParameterResolver: params for Surname: " + surName + " GivenName: " + givenName + "BirthDate: " + dateOfBirth + " not found!"); //try a search with surname, givenname only params = (LPRParams) namedMap.get(surName + "," + givenName + "," + XSD_BIRTHDATEBLANKATTR); if(null == params) { Logger.debug("XMLLoginParameterResolver: params for Surname: " + surName + " GivenName: " + givenName + " not found!"); return null; } } if (params.getEnabled()) { Logger.info("XMLLoginParameterResolver: Surname:" + surName + " GivenName: " + givenName + " found in list; user is enabled"); Logger.debug("XMLLoginParameterResolver: using: " + params.toString()); return params; } Logger.info( "XMLLoginParameterResolver: SurName:" + surName + " GivenName: " + givenName + "found in list; user is NOT enabled"); return null; } //public static final String XSD_MAPPING = "Mapping"; //public static final String XSD_DOCELEM = "MOAIdentities"; public static final String XSD_IDELEM = "Identity"; public static final String XSD_NAMEDIDELEM = "NamedIdentity"; public static final String XSD_BPKIDELEM = "bPKIdentity"; public static final String XSD_PARAMELEM = "Parameters"; public static final String XSD_SURNAMEATTR = "SurName"; public static final String XSD_GIVENNAMEATTR = "GivenName"; public static final String XSD_BIRTHDATEATTR = "BirthDate"; public static final String XSD_BIRTHDATEBLANKATTR = "any"; public static final String XSD_BPKATTR = "bPK"; public static final String XSD_UNATTR = "UN"; public static final String XSD_PWATTR = "PW"; public static final String XSD_PARAM1ATTR = "Param1"; public static final String XSD_PARAM2ATTR = "Param2"; public static final String XSD_PARAM3ATTR = "Param3"; private Map bPKMap; private Map namedMap; private boolean isConfigured = false; }