Skip to content

Commit 76071c8

Browse files
authored
v2.1 (#56)
* 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)
1 parent ee678ef commit 76071c8

18 files changed

Lines changed: 609 additions & 167 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
All notable changes to this project will be documented in this file.
33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

5+
## [2.1] - 2021-07-07
6+
7+
### Added
8+
- AuthenticationIdentity.getDateOfBirth() to get person birthdate (if available).
9+
- Add library version number and Java major release number to User-Agent header of outgoing requests
10+
511
## [2.0] - 2020-11-20
612

713
### Changed

README.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ SemanticsIdentifier semanticsIdentifier = new SemanticsIdentifier(
156156
// (PAS-passport, IDC-national identity card or PNO - (national) personal number)
157157
SemanticsIdentifier.IdentityType.PNO,
158158
SemanticsIdentifier.CountryCode.EE, // 2 character ISO 3166-1 alpha-2 country code
159-
"10101010005"); // identifier (according to country and identity type reference)
159+
"30303039914"); // identifier (according to country and identity type reference)
160160
161161
// For security reasons a new hash value must be created for each new authentication request
162162
AuthenticationHash authenticationHash = AuthenticationHash.generateRandomHash();
@@ -200,7 +200,7 @@ String verificationCode = authenticationHash.calculateVerificationCode();
200200
201201
SmartIdAuthenticationResponse authenticationResponse = client
202202
.createAuthentication()
203-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
203+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
204204
.withAuthenticationHash(authenticationHash)
205205
.withCertificateLevel("QUALIFIED")
206206
.withAllowedInteractionsOrder(Collections.singletonList(
@@ -236,7 +236,11 @@ AuthenticationIdentity authIdentity = authenticationResponseValidator.validate(a
236236
String givenName = authIdentity.getGivenName(); // e.g. Mari-Liis"
237237
String surname = authIdentity.getSurname(); // e.g. "Männik"
238238
String identityCode = authIdentity.getIdentityCode(); // e.g. "47101010033"
239-
String country = authIdentity.getCountry(); // e.g. "EE"
239+
String country = authIdentity.getCountry(); // e.g. "EE", "LV", "LT"
240+
241+
// Date-of-birth is extracted from certificate attribute or parsed from national identity number
242+
// Value is present for all Estonian and Lithuanian persons but not for all Latvian certificates
243+
Optional<LocalDate> dateOfBirth = authIdentity.getDateOfBirth();
240244
```
241245

242246

@@ -250,7 +254,7 @@ To fetch the certificate you can use documentNumber.
250254
```
251255
SmartIdCertificate responseWithSigningCertificate = client
252256
.getCertificate()
253-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q") // returned as authentication result
257+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q") // returned as authentication result
254258
.withCertificateLevel("QUALIFIED")
255259
.fetch();
256260
@@ -287,7 +291,7 @@ String verificationCode = hashToSign.calculateVerificationCode();
287291
288292
SmartIdSignature smartIdSignature = client
289293
.createSignature()
290-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q") // returned as authentication result
294+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q") // returned as authentication result
291295
.withSignableHash(hashToSign)
292296
.withCertificateLevel("QUALIFIED")
293297
.withAllowedInteractionsOrder(asList(
@@ -331,7 +335,7 @@ Every Smart-ID app supports this interaction flow and there is no need to provid
331335
```
332336
SmartIdSignature smartIdSignature = client
333337
.createSignature()
334-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
338+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
335339
.withSignableHash(hashToSign)
336340
.withCertificateLevel("QUALIFIED")
337341
.withAllowedInteractionsOrder(Collections.singletonList(
@@ -353,7 +357,7 @@ If user's app doesn't support displaying verification code choice then system fa
353357
try {
354358
SmartIdSignature smartIdSignature = client
355359
.createSignature()
356-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
360+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
357361
.withSignableHash(hashToSign)
358362
.withCertificateLevel("QUALIFIED")
359363
.withAllowedInteractionsOrder(Arrays.asList(
@@ -376,7 +380,7 @@ If the Smart-ID app in user's smart device doesn't support this feature then the
376380
```
377381
SmartIdSignature smartIdSignature = client
378382
.createSignature()
379-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
383+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
380384
.withSignableHash(hashToSign)
381385
.withCertificateLevel("QUALIFIED")
382386
.withAllowedInteractionsOrder(asList(
@@ -404,7 +408,7 @@ If user picks wrong verification code then the session is cancelled and library
404408
```
405409
SmartIdSignature smartIdSignature = client
406410
.createSignature()
407-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
411+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
408412
.withSignableHash(hashToSign)
409413
.withCertificateLevel("QUALIFIED")
410414
.withAllowedInteractionsOrder(asList(
@@ -435,7 +439,7 @@ If End User's phone doesn't support required flow the library throws `RequiredIn
435439
try {
436440
client
437441
.createSignature()
438-
.withDocumentNumber("PNOEE-10101010005-Z1B2-Q")
442+
.withDocumentNumber("PNOEE-30303039914-5QSV-Q")
439443
.withSignableHash(hashToSign)
440444
.withCertificateLevel("QUALIFIED")
441445
.withAllowedInteractionsOrder(Collections.singletonList(

pom.xml

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<groupId>ee.sk.smartid</groupId>
88
<artifactId>smart-id-java-client</artifactId>
99
<packaging>jar</packaging>
10-
<version>1.0-SNAPSHOT</version>
10+
<version>2.0-SNAPSHOT</version>
1111

1212
<name>Smart-ID Java client</name>
1313
<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>
@@ -62,18 +62,18 @@
6262
<dependency>
6363
<groupId>com.fasterxml.jackson.core</groupId>
6464
<artifactId>jackson-databind</artifactId>
65-
<version>2.11.3</version>
65+
<version>2.12.3</version>
6666
</dependency>
6767
<!-- manually added what was excluded above -->
6868
<dependency>
6969
<groupId>com.fasterxml.jackson.module</groupId>
7070
<artifactId>jackson-module-jaxb-annotations</artifactId>
71-
<version>2.11.3</version>
71+
<version>2.12.3</version>
7272
</dependency>
7373
<dependency>
7474
<groupId>com.fasterxml.jackson.core</groupId>
7575
<artifactId>jackson-annotations</artifactId>
76-
<version>2.11.3</version>
76+
<version>2.12.3</version>
7777
</dependency>
7878
<dependency>
7979
<groupId>org.slf4j</groupId>
@@ -140,6 +140,12 @@
140140
<scope>test</scope>
141141
</dependency>
142142

143+
<dependency>
144+
<groupId>org.bouncycastle</groupId>
145+
<artifactId>bcprov-jdk15on</artifactId>
146+
<version>1.68</version>
147+
</dependency>
148+
143149
<!-- comment in if you want to configure client with RestEasy in tests
144150
<dependency>
145151
<groupId>org.jboss.resteasy</groupId>
@@ -255,6 +261,19 @@
255261
<artifactId>spotbugs-maven-plugin</artifactId>
256262
<version>3.1.12</version>
257263
</plugin>
264+
265+
<plugin>
266+
<groupId>org.apache.maven.plugins</groupId>
267+
<artifactId>maven-jar-plugin</artifactId>
268+
<configuration>
269+
<archive>
270+
<manifest>
271+
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
272+
</manifest>
273+
</archive>
274+
</configuration>
275+
</plugin>
276+
258277
</plugins>
259278
</build>
260279

src/main/java/ee/sk/smartid/AuthenticationIdentity.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,24 @@
2626
* #L%
2727
*/
2828

29-
public class AuthenticationIdentity {
29+
import java.security.cert.X509Certificate;
30+
import java.time.LocalDate;
31+
import java.util.Optional;
3032

33+
public class AuthenticationIdentity {
3134
private String givenName;
3235
private String surname;
3336
private String identityNumber;
3437
private String country;
38+
private X509Certificate authCertificate;
39+
private LocalDate dateOfBirth;
40+
41+
public AuthenticationIdentity() {
42+
}
43+
44+
public AuthenticationIdentity(X509Certificate authCertificate) {
45+
this.authCertificate = authCertificate;
46+
}
3547

3648
public String getGivenName() {
3749
return givenName;
@@ -49,11 +61,19 @@ public void setSurname(String surname) {
4961
this.surname = surname;
5062
}
5163

64+
/**
65+
* Instead use:
66+
* @see this#getSurname()
67+
*/
5268
@Deprecated
5369
public String getSurName() {
5470
return surname;
5571
}
5672

73+
/**
74+
* Instead use:
75+
* @see this#setSurname(String)
76+
*/
5777
@Deprecated
5878
public void setSurName(String surname) {
5979
this.surname = surname;
@@ -82,4 +102,27 @@ public String getCountry() {
82102
public void setCountry(String country) {
83103
this.country = country;
84104
}
105+
106+
public X509Certificate getAuthCertificate() {
107+
return authCertificate;
108+
}
109+
110+
public void setAuthCertificate(X509Certificate authCertificate) {
111+
this.authCertificate = authCertificate;
112+
}
113+
114+
/**
115+
* Person date of birth.
116+
* NB! This information is not available for some Latvian certificates.
117+
*
118+
* @return Date of birth if this information is available in authentication response or empty optional.
119+
*/
120+
public Optional<LocalDate> getDateOfBirth() {
121+
return Optional.ofNullable(dateOfBirth);
122+
}
123+
124+
public void setDateOfBirth(LocalDate dateOfBirth) {
125+
this.dateOfBirth = dateOfBirth;
126+
}
127+
85128
}

src/main/java/ee/sk/smartid/AuthenticationResponseValidator.java

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import ee.sk.smartid.exception.UnprocessableSmartIdResponseException;
3030
import ee.sk.smartid.exception.permanent.SmartIdClientException;
3131
import ee.sk.smartid.exception.useraccount.CertificateLevelMismatchException;
32+
import ee.sk.smartid.util.CertificateAttributeUtil;
33+
import ee.sk.smartid.util.NationalIdentityNumberUtil;
3234
import org.apache.commons.codec.binary.Base64;
3335
import org.apache.commons.lang3.ArrayUtils;
3436
import org.apache.commons.lang3.StringUtils;
@@ -47,10 +49,8 @@
4749
import java.security.cert.CertificateException;
4850
import java.security.cert.CertificateFactory;
4951
import java.security.cert.X509Certificate;
50-
import java.util.ArrayList;
51-
import java.util.Date;
52-
import java.util.Enumeration;
53-
import java.util.List;
52+
import java.time.LocalDate;
53+
import java.util.*;
5454

5555
import static java.util.Arrays.asList;
5656

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

273-
AuthenticationIdentity constructAuthenticationIdentity(X509Certificate certificate) {
274-
AuthenticationIdentity identity = new AuthenticationIdentity();
273+
public AuthenticationIdentity constructAuthenticationIdentity(X509Certificate certificate) {
274+
AuthenticationIdentity identity = new AuthenticationIdentity(certificate);
275275
try {
276276
LdapName ln = new LdapName(certificate.getSubjectDN().getName());
277277
for(Rdn rdn : ln.getRdns()) {
278-
if(rdn.getType().equalsIgnoreCase("GIVENNAME")) {
278+
if (rdn.getType().equalsIgnoreCase("GIVENNAME")) {
279279
identity.setGivenName(rdn.getValue().toString());
280-
} else if(rdn.getType().equalsIgnoreCase("SURNAME")) {
280+
}
281+
else if (rdn.getType().equalsIgnoreCase("SURNAME")) {
281282
identity.setSurname(rdn.getValue().toString());
282-
} else if(rdn.getType().equalsIgnoreCase("SERIALNUMBER")) {
283+
}
284+
else if (rdn.getType().equalsIgnoreCase("SERIALNUMBER")) {
283285
identity.setIdentityNumber(rdn.getValue().toString().split("-", 2)[1]);
284-
} else if(rdn.getType().equalsIgnoreCase("C")) {
286+
}
287+
else if (rdn.getType().equalsIgnoreCase("C")) {
285288
identity.setCountry(rdn.getValue().toString());
286289
}
287-
288290
}
291+
292+
identity.setDateOfBirth(getDateOfBirth(identity));
293+
289294
return identity;
290-
} catch (InvalidNameException e) {
295+
}
296+
catch (InvalidNameException e) {
291297
logger.error("Error getting authentication identity from the certificate", e);
292298
throw new SmartIdClientException("Error getting authentication identity from the certificate", e);
293299
}
294300
}
301+
302+
private LocalDate getDateOfBirth(AuthenticationIdentity identity) {
303+
return Optional.ofNullable(
304+
CertificateAttributeUtil.getDateOfBirth(identity.getAuthCertificate()))
305+
.orElse(NationalIdentityNumberUtil.getDateOfBirth(identity));
306+
}
307+
295308
}

src/main/java/ee/sk/smartid/rest/SmartIdRestConnector.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public void setSessionStatusResponseSocketOpenTime(TimeUnit sessionStatusRespons
174174
this.sessionStatusResponseSocketOpenTimeValue = sessionStatusResponseSocketOpenTimeValue;
175175
}
176176

177-
private Invocation.Builder prepareClient(URI uri) {
177+
protected Invocation.Builder prepareClient(URI uri) {
178178
Client client;
179179
if (this.configuredClient == null) {
180180
ClientBuilder clientBuilder = ClientBuilder.newBuilder();
@@ -194,7 +194,26 @@ private Invocation.Builder prepareClient(URI uri) {
194194
.register(new LoggingFilter())
195195
.target(uri)
196196
.request()
197-
.accept(APPLICATION_JSON_TYPE);
197+
.accept(APPLICATION_JSON_TYPE)
198+
.header("User-Agent", buildUserAgentString());
199+
}
200+
201+
protected String buildUserAgentString() {
202+
return "smart-id-java-client/" + getClientVersion() + " (Java/" + getJdkMajorVersion() + ")";
203+
}
204+
205+
protected String getClientVersion() {
206+
String clientVersion = getClass().getPackage().getImplementationVersion();
207+
return clientVersion == null ? "-" : clientVersion;
208+
}
209+
210+
protected String getJdkMajorVersion() {
211+
try {
212+
return System.getProperty("java.version").split("_")[0];
213+
}
214+
catch (Exception e) {
215+
return "-";
216+
}
198217
}
199218

200219
private CertificateChoiceResponse postCertificateRequest(URI uri, CertificateRequest request) {

src/main/java/ee/sk/smartid/rest/dao/SessionStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class SessionStatus implements Serializable {
3939
private SessionSignature signature;
4040

4141
private SessionCertificate cert;
42-
private String[] ignoredProperties;
42+
private String[] ignoredProperties = {};
4343

4444
private String interactionFlowUsed;
4545

0 commit comments

Comments
 (0)