Skip to content

Commit

Permalink
v2.1 (#56)
Browse files Browse the repository at this point in the history
* Bump junit from 4.12 to 4.13.1 (#48)
* Start using new testnumbers
* Add method to get person birthdate (if available) (#54)
* Add library version number and Java major release number to User-Aget header of outgoing requests (#55)
  • Loading branch information
jalukse authored Jul 7, 2021
1 parent ee678ef commit 76071c8
Show file tree
Hide file tree
Showing 18 changed files with 609 additions and 167 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [2.1] - 2021-07-07

### Added
- AuthenticationIdentity.getDateOfBirth() to get person birthdate (if available).
- Add library version number and Java major release number to User-Agent header of outgoing requests

## [2.0] - 2020-11-20

### Changed
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ SemanticsIdentifier semanticsIdentifier = new SemanticsIdentifier(
// (PAS-passport, IDC-national identity card or PNO - (national) personal number)
SemanticsIdentifier.IdentityType.PNO,
SemanticsIdentifier.CountryCode.EE, // 2 character ISO 3166-1 alpha-2 country code
"10101010005"); // identifier (according to country and identity type reference)
"30303039914"); // identifier (according to country and identity type reference)
// For security reasons a new hash value must be created for each new authentication request
AuthenticationHash authenticationHash = AuthenticationHash.generateRandomHash();
Expand Down Expand Up @@ -200,7 +200,7 @@ String verificationCode = authenticationHash.calculateVerificationCode();
SmartIdAuthenticationResponse authenticationResponse = client
.createAuthentication()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withAuthenticationHash(authenticationHash)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(Collections.singletonList(
Expand Down Expand Up @@ -236,7 +236,11 @@ AuthenticationIdentity authIdentity = authenticationResponseValidator.validate(a
String givenName = authIdentity.getGivenName(); // e.g. Mari-Liis"
String surname = authIdentity.getSurname(); // e.g. "Männik"
String identityCode = authIdentity.getIdentityCode(); // e.g. "47101010033"
String country = authIdentity.getCountry(); // e.g. "EE"
String country = authIdentity.getCountry(); // e.g. "EE", "LV", "LT"
// Date-of-birth is extracted from certificate attribute or parsed from national identity number
// Value is present for all Estonian and Lithuanian persons but not for all Latvian certificates
Optional<LocalDate> dateOfBirth = authIdentity.getDateOfBirth();
```


Expand All @@ -250,7 +254,7 @@ To fetch the certificate you can use documentNumber.
```
SmartIdCertificate responseWithSigningCertificate = client
.getCertificate()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q") // returned as authentication result
.withDocumentNumber("PNOEE-30303039914-5QSV-Q") // returned as authentication result
.withCertificateLevel("QUALIFIED")
.fetch();
Expand Down Expand Up @@ -287,7 +291,7 @@ String verificationCode = hashToSign.calculateVerificationCode();
SmartIdSignature smartIdSignature = client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q") // returned as authentication result
.withDocumentNumber("PNOEE-30303039914-5QSV-Q") // returned as authentication result
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(asList(
Expand Down Expand Up @@ -331,7 +335,7 @@ Every Smart-ID app supports this interaction flow and there is no need to provid
```
SmartIdSignature smartIdSignature = client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(Collections.singletonList(
Expand All @@ -353,7 +357,7 @@ If user's app doesn't support displaying verification code choice then system fa
try {
SmartIdSignature smartIdSignature = client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(Arrays.asList(
Expand All @@ -376,7 +380,7 @@ If the Smart-ID app in user's smart device doesn't support this feature then the
```
SmartIdSignature smartIdSignature = client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(asList(
Expand Down Expand Up @@ -404,7 +408,7 @@ If user picks wrong verification code then the session is cancelled and library
```
SmartIdSignature smartIdSignature = client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(asList(
Expand Down Expand Up @@ -435,7 +439,7 @@ If End User's phone doesn't support required flow the library throws `RequiredIn
try {
client
.createSignature()
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
.withSignableHash(hashToSign)
.withCertificateLevel("QUALIFIED")
.withAllowedInteractionsOrder(Collections.singletonList(
Expand Down
27 changes: 23 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<groupId>ee.sk.smartid</groupId>
<artifactId>smart-id-java-client</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>

<name>Smart-ID Java client</name>
<description>Smart-ID Java client is a Java library that can be used for easy integration of the Smart-ID solution to information systems or e-services</description>
Expand Down Expand Up @@ -62,18 +62,18 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
<version>2.12.3</version>
</dependency>
<!-- manually added what was excluded above -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.11.3</version>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.3</version>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down Expand Up @@ -140,6 +140,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>

<!-- comment in if you want to configure client with RestEasy in tests
<dependency>
<groupId>org.jboss.resteasy</groupId>
Expand Down Expand Up @@ -255,6 +261,19 @@
<artifactId>spotbugs-maven-plugin</artifactId>
<version>3.1.12</version>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>

</plugins>
</build>

Expand Down
45 changes: 44 additions & 1 deletion src/main/java/ee/sk/smartid/AuthenticationIdentity.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,24 @@
* #L%
*/

public class AuthenticationIdentity {
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.util.Optional;

public class AuthenticationIdentity {
private String givenName;
private String surname;
private String identityNumber;
private String country;
private X509Certificate authCertificate;
private LocalDate dateOfBirth;

public AuthenticationIdentity() {
}

public AuthenticationIdentity(X509Certificate authCertificate) {
this.authCertificate = authCertificate;
}

public String getGivenName() {
return givenName;
Expand All @@ -49,11 +61,19 @@ public void setSurname(String surname) {
this.surname = surname;
}

/**
* Instead use:
* @see this#getSurname()
*/
@Deprecated
public String getSurName() {
return surname;
}

/**
* Instead use:
* @see this#setSurname(String)
*/
@Deprecated
public void setSurName(String surname) {
this.surname = surname;
Expand Down Expand Up @@ -82,4 +102,27 @@ public String getCountry() {
public void setCountry(String country) {
this.country = country;
}

public X509Certificate getAuthCertificate() {
return authCertificate;
}

public void setAuthCertificate(X509Certificate authCertificate) {
this.authCertificate = authCertificate;
}

/**
* Person date of birth.
* NB! This information is not available for some Latvian certificates.
*
* @return Date of birth if this information is available in authentication response or empty optional.
*/
public Optional<LocalDate> getDateOfBirth() {
return Optional.ofNullable(dateOfBirth);
}

public void setDateOfBirth(LocalDate dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

}
37 changes: 25 additions & 12 deletions src/main/java/ee/sk/smartid/AuthenticationResponseValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import ee.sk.smartid.exception.UnprocessableSmartIdResponseException;
import ee.sk.smartid.exception.permanent.SmartIdClientException;
import ee.sk.smartid.exception.useraccount.CertificateLevelMismatchException;
import ee.sk.smartid.util.CertificateAttributeUtil;
import ee.sk.smartid.util.NationalIdentityNumberUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -47,10 +49,8 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.time.LocalDate;
import java.util.*;

import static java.util.Arrays.asList;

Expand Down Expand Up @@ -270,26 +270,39 @@ private static byte[] addPadding(byte[] digestInfoPrefix, byte[] digest) {
return ArrayUtils.addAll(digestInfoPrefix, digest);
}

AuthenticationIdentity constructAuthenticationIdentity(X509Certificate certificate) {
AuthenticationIdentity identity = new AuthenticationIdentity();
public AuthenticationIdentity constructAuthenticationIdentity(X509Certificate certificate) {
AuthenticationIdentity identity = new AuthenticationIdentity(certificate);
try {
LdapName ln = new LdapName(certificate.getSubjectDN().getName());
for(Rdn rdn : ln.getRdns()) {
if(rdn.getType().equalsIgnoreCase("GIVENNAME")) {
if (rdn.getType().equalsIgnoreCase("GIVENNAME")) {
identity.setGivenName(rdn.getValue().toString());
} else if(rdn.getType().equalsIgnoreCase("SURNAME")) {
}
else if (rdn.getType().equalsIgnoreCase("SURNAME")) {
identity.setSurname(rdn.getValue().toString());
} else if(rdn.getType().equalsIgnoreCase("SERIALNUMBER")) {
}
else if (rdn.getType().equalsIgnoreCase("SERIALNUMBER")) {
identity.setIdentityNumber(rdn.getValue().toString().split("-", 2)[1]);
} else if(rdn.getType().equalsIgnoreCase("C")) {
}
else if (rdn.getType().equalsIgnoreCase("C")) {
identity.setCountry(rdn.getValue().toString());
}

}

identity.setDateOfBirth(getDateOfBirth(identity));

return identity;
} catch (InvalidNameException e) {
}
catch (InvalidNameException e) {
logger.error("Error getting authentication identity from the certificate", e);
throw new SmartIdClientException("Error getting authentication identity from the certificate", e);
}
}

private LocalDate getDateOfBirth(AuthenticationIdentity identity) {
return Optional.ofNullable(
CertificateAttributeUtil.getDateOfBirth(identity.getAuthCertificate()))
.orElse(NationalIdentityNumberUtil.getDateOfBirth(identity));
}

}
23 changes: 21 additions & 2 deletions src/main/java/ee/sk/smartid/rest/SmartIdRestConnector.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public void setSessionStatusResponseSocketOpenTime(TimeUnit sessionStatusRespons
this.sessionStatusResponseSocketOpenTimeValue = sessionStatusResponseSocketOpenTimeValue;
}

private Invocation.Builder prepareClient(URI uri) {
protected Invocation.Builder prepareClient(URI uri) {
Client client;
if (this.configuredClient == null) {
ClientBuilder clientBuilder = ClientBuilder.newBuilder();
Expand All @@ -194,7 +194,26 @@ private Invocation.Builder prepareClient(URI uri) {
.register(new LoggingFilter())
.target(uri)
.request()
.accept(APPLICATION_JSON_TYPE);
.accept(APPLICATION_JSON_TYPE)
.header("User-Agent", buildUserAgentString());
}

protected String buildUserAgentString() {
return "smart-id-java-client/" + getClientVersion() + " (Java/" + getJdkMajorVersion() + ")";
}

protected String getClientVersion() {
String clientVersion = getClass().getPackage().getImplementationVersion();
return clientVersion == null ? "-" : clientVersion;
}

protected String getJdkMajorVersion() {
try {
return System.getProperty("java.version").split("_")[0];
}
catch (Exception e) {
return "-";
}
}

private CertificateChoiceResponse postCertificateRequest(URI uri, CertificateRequest request) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ee/sk/smartid/rest/dao/SessionStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class SessionStatus implements Serializable {
private SessionSignature signature;

private SessionCertificate cert;
private String[] ignoredProperties;
private String[] ignoredProperties = {};

private String interactionFlowUsed;

Expand Down
Loading

0 comments on commit 76071c8

Please sign in to comment.