diff options
Diffstat (limited to 'src/main/java/at/gv/util/data/ElectronicIdentity.java')
-rw-r--r-- | src/main/java/at/gv/util/data/ElectronicIdentity.java | 659 |
1 files changed, 659 insertions, 0 deletions
diff --git a/src/main/java/at/gv/util/data/ElectronicIdentity.java b/src/main/java/at/gv/util/data/ElectronicIdentity.java new file mode 100644 index 0000000..4483e86 --- /dev/null +++ b/src/main/java/at/gv/util/data/ElectronicIdentity.java @@ -0,0 +1,659 @@ +/* + * Copyright 2011 Federal Chancellery Austria and + * Graz University of Technology + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package at.gv.util.data; + +import java.io.FileOutputStream; +import java.io.Serializable; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.text.ParseException; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.time.DateFormatUtils; +import org.apache.commons.lang.time.DateUtils; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.util.BpkUtil; +import at.gv.util.DOMUtils; +import at.gv.util.MiscUtil; +import at.gv.util.ToStringUtil; +import at.gv.util.ex.EgovUtilException; +import at.gv.util.ex.InternalErrorException; +import at.gv.util.xsd.mandate.Mandate; +import at.gv.util.xsd.persondata.IdentificationType; +import at.gv.util.xsd.persondata.PersonDataType; +import at.gv.util.xsd.persondata.PhysicalPersonType; +import at.gv.util.xsd.saml.assertion.AssertionType; +import at.gv.util.xsd.saml.assertion.AttributeStatementType; +import at.gv.util.xsd.saml.assertion.AttributeType; +import at.gv.util.xsd.saml.assertion.NameIdentifierType; +import at.gv.util.xsd.saml.assertion.ObjectFactory; +import at.gv.util.xsd.saml.assertion.StatementAbstractType; +import at.gv.util.xsd.saml.assertion.SubjectConfirmationType; +import at.gv.util.xsd.saml.assertion.SubjectType; + +/** + * @author <a href="mailto:arne.tauber@egiz.gv.at">Arne Tauber</a> + * @author <a href="mailto:thomas.knall@iaik.tugraz.at">Thomas Knall</a> + */ +public final class ElectronicIdentity implements Serializable, Empty, RoleContainer { + + private static final long serialVersionUID = 1L; + + private Logger log = Logger.getLogger(this.getClass().getName()); + + private static final String FIRSTNAME = "firstname"; + private static final String LASTNAME = "lastname"; + private static final String TITLE = "title"; + private static final String DATEOFBIRTH = "dateofbirth"; + private static final String EMAIL = "email"; + private static final String BASEID = "baseid"; + private static final String BPK = "bpk"; + private static final String WBPK = "wbpk"; + private static final String VZBPK = "vzbpk"; + private static final String ZBPK = "zbpk"; + private static final String BKU_URL = "bkuurl"; + private static final String ROLES = "roles"; + private static final String ROLE = "role"; + private static final String NAME_QUALIFIER = "namequalifier"; + private static final String NAME_IDENTIFIER = "nameidentifier"; + private static final String MANDATE_ENABLED = "mandateenabled"; + + private static final String BPK_NAME_QUALIFIER = "urn:publicid:gv.at:cdid+bpk"; + private static final String WBPK_NAME_QUALIFIER_PREFIX = "urn:publicid:gv.at:wbpk"; + private static final String BASE_NAME_QUALIFIER = "urn:publicid:gv.at:baseid"; + + private String firstName; + private String title; + private String lastName; + private Date dateOfBirth; + private String bpk; + private String wbpk; + private String baseId; + private String vzbpk; + private String zbpk; + private String email; + private String bkuURL; + private String nameQualifier; + private String nameIdentifier; + private Set<String> roles; + private Object userdefinedData; + private AssertionType samlAssertion; + private Mandate mandate; + + public String getTitle() { + return this.title; + } + + public Object getUserdefinedData() { + return this.userdefinedData; + } + + public void setUserdefinedData(Object userdefinedData) { + this.userdefinedData = userdefinedData; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBkuURL() { + return this.bkuURL; + } + + public void setBkuURL(String bkuURL) { + this.bkuURL = bkuURL; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getWbpk() { + return this.wbpk; + } + + public void setWbpk(String wbpk) { + this.wbpk = wbpk; + } + + public String getNameQualifier() { + return this.nameQualifier; + } + + public void setNameQualifier(String nameQualifier) { + this.nameQualifier = nameQualifier; + } + + public String getNameIdentifier() { + return this.nameIdentifier; + } + + public void setNameIdentifier(String nameIdentifier) { + this.nameIdentifier = nameIdentifier; + } + + public String getZbpk() { + return this.zbpk; + } + + public void setZbpk(String zbpk) { + this.zbpk = zbpk; + } + + public String getVzbpk() { + return this.vzbpk; + } + + public void setVzbpk(String vzbpk) { + this.vzbpk = vzbpk; + } + + public String getBaseId() { + return this.baseId; + } + + public void setBaseId(String baseId) { + this.baseId = baseId; + } + + public String getBpk() { + return this.bpk; + } + + public void setBpk(String bpk) { + this.bpk = bpk; + } + + public AssertionType getSamlAssertion() { + return this.samlAssertion; + } + + public Date getDateOfBirth() { + return this.dateOfBirth; + } + + public void setDateOfBirth(Date dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getFirstName() { + return this.firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return this.lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Set<String> getRoles() { + return this.roles; + } + + public void setRoles(Set<String> roles) { + MiscUtil.assertNotNull(roles, "Roles"); + this.roles = roles; + } + + public ElectronicIdentity addRole(String role) { + MiscUtil.assertNotEmpty(role, "Role"); + this.roles.add(role); + return this; + } + + public ElectronicIdentity() { + } + + public ElectronicIdentity(String firstName, String lastName, Date dateOfBirth) { + this(); + this.setFirstName(firstName); + this.setLastName(lastName); + this.setDateOfBirth(dateOfBirth); + } + + public ElectronicIdentity(String firstName, String lastName, String email) { + this(); + this.setFirstName(firstName); + this.setLastName(lastName); + this.setEmail(email); + } + + private void updateAll() { + if (this.getNameQualifier() != null + && this.getNameQualifier().startsWith(WBPK_NAME_QUALIFIER_PREFIX) + && MiscUtil.isEmpty(this.getNameIdentifier())) { + log.debug("NameQualifier starts with \"" + WBPK_NAME_QUALIFIER_PREFIX + + "\" and BaseId is present. Calculating NameIdentifier as wbpk."); + this.nameIdentifier = BpkUtil.calcWBPK(this.getBaseId(), + this.getNameQualifier()); + } + + if (this.getNameQualifier() != null + && this.getNameQualifier().startsWith(WBPK_NAME_QUALIFIER_PREFIX) + && MiscUtil.isEmpty(this.getWbpk()) + && MiscUtil.isNotEmpty(this.getNameIdentifier())) { + log.debug("NameQualifier starts with \"" + WBPK_NAME_QUALIFIER_PREFIX + + "\". We have a wbpk."); + this.wbpk = this.getNameIdentifier(); + } + + if (BPK_NAME_QUALIFIER.equals(this.getNameQualifier()) + && MiscUtil.isEmpty(this.getBpk()) + && MiscUtil.isNotEmpty(this.getNameIdentifier())) { + log.debug("NameQualifier equals to \"" + BPK_NAME_QUALIFIER + + "\". We have a bpk."); + this.bpk = this.getNameIdentifier(); + } + + if (MiscUtil.isNotEmpty(this.getBaseId())) { + log.debug("BaseId present -> calculating zbpk"); + this.zbpk = BpkUtil.calcZBPK(this.getBaseId()); + } + + } + + void setSamlAssertion(AssertionType samlAssertion) { + this.samlAssertion = samlAssertion; + } + + public ElectronicIdentity(Document doc) throws EgovUtilException { + this(doc, false); + } + + public ElectronicIdentity(Document doc, boolean isMOAIDAssertion) throws EgovUtilException { + this(); + try { + MiscUtil.assertNotNull(doc, "Document"); + + JAXBContext ctx = JAXBContext.newInstance(AssertionType.class + .getPackage().getName()); + JAXBElement<AssertionType> assertionElement = (JAXBElement<AssertionType>) ctx + .createUnmarshaller().unmarshal(doc.getDocumentElement()); + + if (isMOAIDAssertion) { + initializeCitizenCardWithMOAIDAssertion(assertionElement.getValue()); + } else { + initializeCitizenCard(assertionElement.getValue()); + } + + } catch (JAXBException e) { + throw new EgovUtilException(e); + } + } + + public ElectronicIdentity(AssertionType assertion) throws EgovUtilException { + this(assertion, false); + } + + public ElectronicIdentity(AssertionType assertion, boolean isMOAIDAssertion) throws EgovUtilException { + this(); + // debug moa-id response + log.trace("Debug response: " + System.getProperty("debug.moaid.log.path") != null); + if (System.getProperty("debug.moaid.log.path") != null) { + try { + ObjectFactory of = new ObjectFactory(); + JAXBContext ctx = JAXBContext.newInstance(AssertionType.class.getPackage().getName()); + + String file = System.getProperty("debug.moaid.log.path") + "/" + MiscUtil.formatDate(new Date(), "yyyyMMdd-HHmmss") +".xml"; + log.trace("Writing MOA-ID response to: " + file); + FileOutputStream fos = new FileOutputStream(file); + ctx.createMarshaller().marshal(of.createAssertion(assertion), fos); + fos.flush(); + fos.close(); + } catch(Exception e) { + log.debug(e); + } + } + if (isMOAIDAssertion) { + initializeCitizenCardWithMOAIDAssertion(assertion); + } else { + initializeCitizenCard(assertion); + } + } + + private void initializeCitizenCard(AssertionType assertion) + throws EgovUtilException { + MiscUtil.assertNotNull(assertion, "SAMLAssertion"); + + try { + for (StatementAbstractType sat : assertion + .getStatementOrSubjectStatementOrAuthenticationStatement()) { + if (sat instanceof AttributeStatementType) { + AttributeStatementType attrStmt = (AttributeStatementType) sat; + SubjectType subject = attrStmt.getSubject(); + for (JAXBElement<?> subChild : subject.getContent()) { + if (subChild.getValue() instanceof SubjectConfirmationType) { + SubjectConfirmationType sct = (SubjectConfirmationType) subChild + .getValue(); + Element scdNode = (Element) sct.getSubjectConfirmationData(); + Element personNode = (Element) DOMUtils + .getChildElements(scdNode).get(0); + JAXBContext ctx = JAXBContext.newInstance(PhysicalPersonType.class + .getPackage().getName()); + JAXBElement<PhysicalPersonType> pptElement = (JAXBElement<PhysicalPersonType>) ctx + .createUnmarshaller().unmarshal(personNode); + PhysicalPersonType ppt = pptElement.getValue(); + this.baseId = ppt.getIdentification().get(0).getValue().getValue(); + this.firstName = ppt.getName().getGivenName().get(0); + this.lastName = ppt.getName().getFamilyName().get(0).getValue(); + this.dateOfBirth = MiscUtil.parseXMLDate(ppt.getDateOfBirth()); + } + } + } + } + } catch(JAXBException e) { + throw new EgovUtilException(e); + } + } + + private void initializeCitizenCardWithMOAIDAssertion(AssertionType assertion) + throws EgovUtilException { + MiscUtil.assertNotNull(assertion, "SAMLAssertion"); + try { + AttributeStatementType attrStmt = (AttributeStatementType) assertion + .getStatementOrSubjectStatementOrAuthenticationStatement().get(0); + // parse subject + SubjectType subject = attrStmt.getSubject(); + for (JAXBElement<?> subChild : subject.getContent()) { + if (subChild.getValue() instanceof SubjectConfirmationType) { + SubjectConfirmationType sct = (SubjectConfirmationType) subChild + .getValue(); + Element scdNode = (Element) sct.getSubjectConfirmationData(); + if (scdNode.hasChildNodes()) { + Element assertionNode = (Element) DOMUtils.getChildElements(scdNode) + .get(0); + JAXBContext ctx = JAXBContext.newInstance(AssertionType.class.getPackage().getName()); + JAXBElement<AssertionType> assertionElement = (JAXBElement<AssertionType>) ctx + .createUnmarshaller().unmarshal(assertionNode); + AssertionType subjectAssertion = assertionElement.getValue(); + for (StatementAbstractType sat : subjectAssertion + .getStatementOrSubjectStatementOrAuthenticationStatement()) { + if (sat instanceof AttributeStatementType) { + AttributeStatementType ast = (AttributeStatementType) sat; + for (AttributeType attr : ast.getAttribute()) { + if ("bPK".equals(attr.getAttributeName())) { + Element attrValueNode = (Element) attr.getAttributeValue() + .get(0); + Element idNode = (Element) DOMUtils.getChildElements( + attrValueNode).get(0); + ctx = JAXBContext.newInstance(IdentificationType.class + .getPackage().getName()); + JAXBElement<IdentificationType> idElement = (JAXBElement<IdentificationType>) ctx + .createUnmarshaller().unmarshal(idNode); + IdentificationType idt = (IdentificationType) idElement + .getValue(); + //this.setBpk(idt.getValue().getValue()); + } + } + } + } + } + } else if (subChild.getValue() instanceof NameIdentifierType) { + NameIdentifierType nit = (NameIdentifierType) subChild.getValue(); + this.setNameQualifier(nit.getNameQualifier()); + this.setNameIdentifier(nit.getValue()); + } + } + + for (AttributeType attr : attrStmt.getAttribute()) { + if ("PersonData".equals(attr.getAttributeName())) { + Element attrValueNode = (Element) attr.getAttributeValue().get(0); + Element personNode = (Element) DOMUtils.getChildElements( + attrValueNode).get(0); + JAXBContext ctx = JAXBContext.newInstance(PhysicalPersonType.class + .getPackage().getName()); + JAXBElement<PhysicalPersonType> pptElement = (JAXBElement<PhysicalPersonType>) ctx + .createUnmarshaller().unmarshal(personNode); + PhysicalPersonType ppt = pptElement.getValue(); + String baseId = ppt.getIdentification().get(0).getValue().getValue(); + this.setBaseId(baseId); + this.setZbpk(BpkUtil.calcZBPK(baseId)); + this.setVzbpk(BpkUtil.calcVZBPK(baseId)); + this.setDateOfBirth(MiscUtil.parseXMLDate(ppt.getDateOfBirth())); + this.setFirstName(ppt.getName().getGivenName().get(0)); + this.setLastName(ppt.getName().getFamilyName().get(0).getValue()); + } else if ("bkuURL".equals(attr.getAttributeName())) { + Node attrValueNode = (Node) attr.getAttributeValue().get(0); + this.setBkuURL(attrValueNode.getFirstChild().getNodeValue()); + } else if ("Mandate".equals(attr.getAttributeName())) { + Element attrValueNode = (Element) attr.getAttributeValue().get(0); + List mandateElementList = DOMUtils.getChildElements(attrValueNode); + if (mandateElementList != null && mandateElementList.size() > 0) { + // parse mandate + JAXBContext ctx = JAXBContext.newInstance(Mandate.class.getPackage().getName()); + this.mandate = (Mandate) ctx.createUnmarshaller().unmarshal((Element) mandateElementList.get(0)); + } + } + } + } catch (JAXBException e) { + throw new EgovUtilException(e); + } + + } + + /** + * Creates a wrapper for buergerkarte person data.<br/> + * Important note: properties-files are supposed to contain ISO 8859-1 + * character encoding + * + * @param properties + * Properties containing buergerkarte person data as key/value pairs + */ + public ElectronicIdentity(Properties properties) { + this(); + this.evaluateProperties(properties); + } + + /** + * Fills wrapper with buergerkarte person data from a Properties file.<br/> + * Important note: properties-files are supposed to contain ISO 8859-1 + * character encoding + * + * @param properties + * Properties containing buergerkarte person data as key/value pairs + * @throws CannotResetException + */ + private void evaluateProperties(Properties properties) { + if (properties != null) { + this.setFirstName(properties.getProperty(FIRSTNAME)); + this.setLastName(properties.getProperty(LASTNAME)); + if (properties.getProperty(DATEOFBIRTH) != null) { + try { + this.setDateOfBirth(DateUtils.parseDate( + properties.getProperty(DATEOFBIRTH), new String[] { "yyyy-MM-dd", + "dd.MM.yyyy", })); + } catch (ParseException e) { + log.error(e); + } + } + this.setTitle(properties.getProperty(TITLE)); + this.setBpk(properties.getProperty(BPK)); + this.setWbpk(properties.getProperty(WBPK)); + this.setBaseId(properties.getProperty(BASEID)); + this.setNameIdentifier(properties.getProperty(NAME_IDENTIFIER)); + this.setNameQualifier(properties.getProperty(NAME_QUALIFIER)); + if (MiscUtil.isEmpty(this.getBaseId()) + && BASE_NAME_QUALIFIER.equals(this.getNameQualifier())) { + this.setBaseId(this.getNameIdentifier()); + } + this.setEmail(properties.getProperty(EMAIL)); + this.setVzbpk(properties.getProperty(VZBPK)); + this.setZbpk(properties.getProperty(ZBPK)); + this.setBkuURL(properties.getProperty(BKU_URL)); + + String roles = properties.getProperty(ROLES); + if (MiscUtil.isNotEmpty(roles)) { + StringTokenizer tokenizer = new StringTokenizer(roles, ","); + while (tokenizer.hasMoreTokens()) { + String role = StringUtils.trim(tokenizer.nextToken()); + if (MiscUtil.isNotEmpty(role)) { + this.roles.add(role); + } + } + } + String role = StringUtils.trim(properties.getProperty(ROLE)); + if (MiscUtil.isNotEmpty(role)) { + this.roles.add(role); + } + + this.updateAll(); + + } + } + + public void calcBpk(String domain) { + if (MiscUtil.isEmpty(this.getBaseId())) { + throw new InternalErrorException( + "Unable to calculate bpk. BaseId has to be set."); + } + if (MiscUtil.isEmpty(domain)) { + throw new IllegalArgumentException( + "Unable to calculate bpk. Target/sector/domain must not be empty."); + } + this.bpk = BpkUtil.calcBPK(this.getBaseId(), domain); + } + + public void calcWbpk() { + MiscUtil.assertNotEmpty(this.getBaseId(), "BaseId"); + MiscUtil.assertNotEmpty(this.getNameQualifier(), "NameQualifier"); + this.wbpk = BpkUtil.calcWBPK(this.getBaseId(), this.getNameQualifier()); + this.nameIdentifier = this.wbpk; + } + + protected void calcVzbpk(byte[] rsaPublicKey, String domain) { + MiscUtil.assertNotEmpty(domain, "Domain"); + if (MiscUtil.isEmpty(this.getBaseId())) { + throw new InternalErrorException( + "Unable to calculate bpk. BaseId has to be set."); + } + MiscUtil.assertNotEmpty(rsaPublicKey, "RSAPublicKey"); + PublicKey publicKey; + try { + + KeyFactory rsaKeyFac = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rsaPublicKey); + publicKey = (RSAPublicKey) rsaKeyFac.generatePublic(keySpec); + } catch (InvalidKeySpecException e) { + throw new InternalErrorException(e); + } catch (NoSuchAlgorithmException e) { + throw new InternalErrorException(e); + } + this.vzbpk = BpkUtil.calcVZBPK(this.getBaseId(), publicKey); + } + + public void calcVzbpk(byte[] rasPublicKey) { + this.calcVzbpk(rasPublicKey, BpkUtil.SECTOR_DELIVERY); + } + + public void calcVzbpk() { + this.calcVzbpk(BpkUtil.PUBLIC_KEY_ZUSEKOPF_SN01_BASE64.getBytes(), + BpkUtil.SECTOR_DELIVERY); + } + + public void calcZbpk() { + if (MiscUtil.isEmpty(this.getBaseId())) { + throw new InternalErrorException( + "Unable to calculate bpk. BaseId has to be set."); + } + this.setZbpk(BpkUtil.calcZBPK(this.getBaseId())); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("firstName", this.firstName) + .append("lastName", this.lastName) + .append( + "dateOfBirth", + this.dateOfBirth != null ? DateFormatUtils.format(this.dateOfBirth, + "yyyy-MM-dd") : this.dateOfBirth) + .append("title", this.title) + .append("email", this.email) + //.append("baseId", this.baseId) + .append("nameQualifier", this.nameQualifier) + .append("nameIdentifier", this.nameIdentifier) + .append("bpk", this.bpk) + .append("wbpk", this.wbpk) + .append("zbpk", this.zbpk) + .append("vzbpk", this.vzbpk) + .append("bkuURL", this.bkuURL) + .append("userdefinedData", this.userdefinedData) + .append( + "roles", + this.roles != null ? ToStringUtil.toString(this.roles, ", ", "\"") + : null) + .append("samlAssertion", + this.samlAssertion != null ? "<set>" : "<not set>").toString(); + } + + public boolean isEmpty() { + boolean stringsEmpty = MiscUtil.areAllEmpty(this.wbpk, this.nameQualifier, + this.nameIdentifier, this.baseId, this.bpk, this.firstName, + this.lastName, this.vzbpk, this.zbpk, this.email, this.bkuURL); + boolean udEmpty = true; + if (this.userdefinedData != null) { + if (this.userdefinedData instanceof Empty) { + udEmpty = ((Empty) this.userdefinedData).isEmpty(); + } else { + udEmpty = false; + } + } + return stringsEmpty && udEmpty && this.dateOfBirth == null + && MiscUtil.isEmpty(this.roles) && (this.samlAssertion != null); + } + + public boolean hasRole(String role) { + return this.roles.contains(role); + } + + public void setMandate(Mandate mandate) { + this.mandate = mandate; + } + + public Mandate getMandate() { + return mandate; + } + +} |