Skip to content

Commit 23f87ef

Browse files
authored
Merge pull request #57 from getyoti/API-476
API-476: Final tidy up
2 parents 25f8062 + 3d98bcd commit 23f87ef

File tree

10 files changed

+108
-94
lines changed

10 files changed

+108
-94
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@ If you are using Maven, you need to add the following dependency:
9999
<dependency>
100100
<groupId>com.yoti</groupId>
101101
<artifactId>yoti-sdk-impl</artifactId>
102-
<version>1.4.2</version>
102+
<version>1.5.0</version>
103103
</dependency>
104104
```
105105

106106
If you are using Gradle, here is the dependency to add:
107107

108-
`compile group: 'com.yoti', name: 'yoti-sdk-impl', version: '1.4.2'`
108+
`compile group: 'com.yoti', name: 'yoti-sdk-impl', version: '1.5.0'`
109109

110110
You will find all classes packaged under `com.yoti.api`
111111

yoti-sdk-impl/src/main/java/com/yoti/api/client/spi/remote/AttributeConverter.java

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,69 +8,53 @@
88
import java.util.Map;
99
import java.util.Set;
1010

11-
import org.slf4j.Logger;
12-
import org.slf4j.LoggerFactory;
13-
14-
import com.fasterxml.jackson.databind.ObjectMapper;
1511
import com.yoti.api.client.Attribute;
1612
import com.yoti.api.client.spi.remote.proto.AttrProto;
1713
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;
18-
import com.yoti.api.client.spi.remote.proto.ContentTypeProto.ContentType;
1914
import com.yoti.api.client.spi.remote.util.AnchorCertificateParser;
20-
import com.yoti.api.client.spi.remote.util.AnchorType;
2115
import com.yoti.api.client.spi.remote.util.AnchorCertificateParser.AnchorVerifierSourceData;
16+
import com.yoti.api.client.spi.remote.util.AnchorType;
17+
18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
2221

2322
public class AttributeConverter {
2423

2524
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
2625
private static final Logger LOG = LoggerFactory.getLogger(AttributeConverter.class);
2726

28-
29-
public static Attribute convertAttribute(AttrProto.Attribute attribute) throws ParseException, IOException{
30-
if (ContentType.STRING.equals(attribute.getContentType())) {
31-
return new com.yoti.api.client.Attribute(attribute.getName(),
32-
attribute.getValue().toString(DEFAULT_CHARSET),
33-
extractMetadata(attribute, AnchorType.SOURCE),
34-
extractMetadata(attribute, AnchorType.VERIFIER));
35-
} else if (ContentType.DATE.equals(attribute.getContentType())) {
36-
return new com.yoti.api.client.Attribute(attribute.getName(),
37-
DateAttributeValue.parseFrom(attribute.getValue().toByteArray()),
38-
extractMetadata(attribute, AnchorType.SOURCE),
39-
extractMetadata(attribute, AnchorType.VERIFIER));
40-
} else if (ContentType.JPEG.equals(attribute.getContentType())) {
41-
return new com.yoti.api.client.Attribute(attribute.getName(),
42-
new JpegAttributeValue(attribute.getValue().toByteArray()),
43-
extractMetadata(attribute, AnchorType.SOURCE),
44-
extractMetadata(attribute, AnchorType.VERIFIER));
45-
} else if (ContentType.PNG.equals(attribute.getContentType())) {
46-
return new com.yoti.api.client.Attribute(attribute.getName(),
47-
new PngAttributeValue(attribute.getValue().toByteArray()),
48-
extractMetadata(attribute, AnchorType.SOURCE),
49-
extractMetadata(attribute, AnchorType.VERIFIER));
50-
} else if (ContentType.JSON.equals(attribute.getContentType())) {
51-
return new com.yoti.api.client.Attribute(attribute.getName(),
52-
JSON_MAPPER.readValue(attribute.getValue().toString(DEFAULT_CHARSET), Map.class),
53-
extractMetadata(attribute, AnchorType.SOURCE),
54-
extractMetadata(attribute, AnchorType.VERIFIER));
27+
public static Attribute convertAttribute(com.yoti.api.client.spi.remote.proto.AttrProto.Attribute attribute) throws ParseException, IOException {
28+
switch (attribute.getContentType()) {
29+
case STRING:
30+
return attributeWithMetadata(attribute, attribute.getValue().toString(DEFAULT_CHARSET));
31+
case DATE:
32+
return attributeWithMetadata(attribute, DateAttributeValue.parseFrom(attribute.getValue().toByteArray()));
33+
case JPEG:
34+
return attributeWithMetadata(attribute, new JpegAttributeValue(attribute.getValue().toByteArray()));
35+
case PNG:
36+
return attributeWithMetadata(attribute, new PngAttributeValue(attribute.getValue().toByteArray()));
37+
case JSON:
38+
return attributeWithMetadata(attribute, JSON_MAPPER.readValue(attribute.getValue().toString(DEFAULT_CHARSET), Map.class));
39+
default:
40+
LOG.error("Unknown type {} for attribute {}", attribute.getContentType(), attribute.getName());
41+
return attributeWithMetadata(attribute, attribute.getValue().toString(DEFAULT_CHARSET));
5542
}
43+
}
5644

57-
LOG.error("Unknown type {} for attribute {}", attribute.getContentType(), attribute.getName());
58-
return new com.yoti.api.client.Attribute(attribute.getName(),
59-
attribute.getValue().toString(DEFAULT_CHARSET),
60-
extractMetadata(attribute, AnchorType.SOURCE),
61-
extractMetadata(attribute, AnchorType.VERIFIER));
45+
private static Attribute attributeWithMetadata(AttrProto.Attribute attribute, Object value) {
46+
return new Attribute(attribute.getName(), value, extractMetadata(attribute, AnchorType.SOURCE), extractMetadata(attribute, AnchorType.VERIFIER));
6247
}
6348

6449
private static Set<String> extractMetadata(AttrProto.Attribute attribute, AnchorType anchorType) {
6550
Set<String> entries = new HashSet<String>();
6651
for (Anchor anchor : attribute.getAnchorsList()) {
6752
AnchorVerifierSourceData anchorData = AnchorCertificateParser.getTypesFromAnchor(anchor);
68-
if(anchorData.getType().equals(anchorType)) {
53+
if (anchorData.getType().equals(anchorType)) {
6954
entries.addAll(anchorData.getEntries());
7055
}
7156
}
7257
return entries;
7358
}
7459

75-
7660
}

yoti-sdk-impl/src/main/java/com/yoti/api/client/spi/remote/SecureYotiClient.java

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.yoti.api.client.spi.remote;
22

3+
import static javax.crypto.Cipher.DECRYPT_MODE;
4+
35
import static com.yoti.api.client.spi.remote.call.YotiConstants.ASYMMETRIC_CIPHER;
46
import static com.yoti.api.client.spi.remote.call.YotiConstants.BOUNCY_CASTLE_PROVIDER;
57
import static com.yoti.api.client.spi.remote.call.YotiConstants.DEFAULT_CHARSET;
68
import static com.yoti.api.client.spi.remote.call.YotiConstants.SYMMETRIC_CIPHER;
79
import static com.yoti.api.client.spi.remote.util.Validation.notNull;
8-
import static javax.crypto.Cipher.DECRYPT_MODE;
910

1011
import java.io.BufferedReader;
1112
import java.io.IOException;
@@ -27,18 +28,10 @@
2728
import javax.crypto.spec.IvParameterSpec;
2829
import javax.crypto.spec.SecretKeySpec;
2930

30-
import org.bouncycastle.openssl.PEMException;
31-
import org.bouncycastle.openssl.PEMKeyPair;
32-
import org.bouncycastle.openssl.PEMParser;
33-
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
34-
import org.slf4j.Logger;
35-
import org.slf4j.LoggerFactory;
36-
37-
import com.google.protobuf.ByteString;
38-
import com.google.protobuf.InvalidProtocolBufferException;
3931
import com.yoti.api.client.ActivityDetails;
4032
import com.yoti.api.client.ActivityFailureException;
4133
import com.yoti.api.client.AmlException;
34+
import com.yoti.api.client.Attribute;
4235
import com.yoti.api.client.InitialisationException;
4336
import com.yoti.api.client.KeyPairSource;
4437
import com.yoti.api.client.KeyPairSource.StreamVisitor;
@@ -50,10 +43,19 @@
5043
import com.yoti.api.client.spi.remote.call.ProfileService;
5144
import com.yoti.api.client.spi.remote.call.Receipt;
5245
import com.yoti.api.client.spi.remote.call.aml.RemoteAmlService;
53-
import com.yoti.api.client.spi.remote.proto.AttrProto.Attribute;
46+
import com.yoti.api.client.spi.remote.proto.AttrProto;
5447
import com.yoti.api.client.spi.remote.proto.AttributeListProto.AttributeList;
5548
import com.yoti.api.client.spi.remote.proto.EncryptedDataProto.EncryptedData;
5649

50+
import com.google.protobuf.ByteString;
51+
import com.google.protobuf.InvalidProtocolBufferException;
52+
import org.bouncycastle.openssl.PEMException;
53+
import org.bouncycastle.openssl.PEMKeyPair;
54+
import org.bouncycastle.openssl.PEMParser;
55+
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
56+
import org.slf4j.Logger;
57+
import org.slf4j.LoggerFactory;
58+
5759
/**
5860
* YotiClient talking to the Yoti Connect API remotely.
5961
*/
@@ -140,7 +142,7 @@ private void validateReceipt(Receipt receipt) throws ActivityFailureException {
140142
}
141143

142144
private Profile createProfile(byte[] profileBytes, Key secretKey) throws ProfileException {
143-
List<com.yoti.api.client.Attribute> attributeList = new ArrayList<com.yoti.api.client.Attribute>();
145+
List<Attribute> attributeList = new ArrayList<Attribute>();
144146
if (profileBytes != null && profileBytes.length > 0) {
145147
EncryptedData encryptedData = parseProfileContent(profileBytes);
146148
byte[] profileData = decrypt(encryptedData.getCipherText(), secretKey, encryptedData.getIv());
@@ -161,26 +163,22 @@ private Key parseKey(byte[] keyVal) {
161163
return new SecretKeySpec(keyVal, SYMMETRIC_CIPHER);
162164
}
163165

164-
private List<com.yoti.api.client.Attribute> parseProfile(byte[] profileData) throws ProfileException {
165-
List<com.yoti.api.client.Attribute> attributeList = null;
166+
private List<Attribute> parseProfile(byte[] profileData) throws ProfileException {
166167
try {
167168
AttributeList message = AttributeList.parseFrom(profileData);
168-
attributeList = parseAttributes(message);
169+
List<Attribute> attributeList = parseAttributes(message);
169170
LOG.debug("{} attribute(s) parsed", attributeList.size());
171+
return attributeList;
170172
} catch (InvalidProtocolBufferException e) {
171173
throw new ProfileException("Cannot parse profile data", e);
172174
}
173-
return attributeList;
174175
}
175176

176-
private List<com.yoti.api.client.Attribute> parseAttributes(AttributeList message) {
177-
List<com.yoti.api.client.Attribute> parsedAttributes = new ArrayList<com.yoti.api.client.Attribute>();
178-
for (Attribute attribute : message.getAttributesList()) {
177+
private List<Attribute> parseAttributes(AttributeList message) {
178+
List<Attribute> parsedAttributes = new ArrayList<Attribute>();
179+
for (AttrProto.Attribute attribute : message.getAttributesList()) {
179180
try {
180-
com.yoti.api.client.Attribute parsedAttribute = AttributeConverter.convertAttribute(attribute);
181-
if (parsedAttribute != null) {
182-
parsedAttributes.add(parsedAttribute);
183-
}
181+
parsedAttributes.add(AttributeConverter.convertAttribute(attribute));
184182
} catch (IOException e) {
185183
LOG.info("Cannot decode value for attribute {}", attribute.getName());
186184
} catch (ParseException e) {
@@ -191,7 +189,7 @@ private List<com.yoti.api.client.Attribute> parseAttributes(AttributeList messag
191189
}
192190

193191

194-
private Profile createProfile(List<com.yoti.api.client.Attribute> attributeList) {
192+
private Profile createProfile(List<Attribute> attributeList) {
195193
return new SimpleProfile(attributeList);
196194
}
197195

yoti-sdk-impl/src/main/java/com/yoti/api/client/spi/remote/util/AnchorCertificateParser.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.yoti.api.client.spi.remote.util;
22

3+
import static com.yoti.api.client.spi.remote.call.YotiConstants.DEFAULT_CHARSET;
4+
35
import java.io.ByteArrayInputStream;
46
import java.io.IOException;
7+
import java.security.cert.CertificateException;
58
import java.security.cert.CertificateFactory;
69
import java.security.cert.X509Certificate;
710
import java.util.ArrayList;
@@ -10,7 +13,9 @@
1013
import java.util.List;
1114
import java.util.Set;
1215

13-
import org.bouncycastle.asn1.ASN1InputStream;
16+
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;
17+
18+
import com.google.protobuf.ByteString;
1419
import org.bouncycastle.asn1.ASN1OctetString;
1520
import org.bouncycastle.asn1.ASN1Primitive;
1621
import org.bouncycastle.asn1.ASN1TaggedObject;
@@ -19,13 +24,10 @@
1924
import org.slf4j.Logger;
2025
import org.slf4j.LoggerFactory;
2126

22-
import com.google.protobuf.ByteString;
23-
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;
24-
2527
public class AnchorCertificateParser {
28+
2629
private static final Logger LOG = LoggerFactory.getLogger(AnchorCertificateParser.class);
2730

28-
2931
public static AnchorVerifierSourceData getTypesFromAnchor(Anchor anchor) {
3032
Set<String> types = new HashSet<String>(anchor.getOriginServerCertsCount());
3133
AnchorType anchorType = AnchorType.UNKNOWN;
@@ -46,29 +48,29 @@ public static AnchorVerifierSourceData getTypesFromAnchor(Anchor anchor) {
4648
}
4749
types.addAll(extensions);
4850
}
49-
} catch (Exception e) {
51+
} catch (IOException e) {
52+
LOG.warn("Could not extract anchor type from certificate.", e);
53+
} catch (CertificateException e) {
5054
LOG.warn("Could not extract anchor type from certificate.", e);
5155
}
5256

5357
return new AnchorVerifierSourceData(types, anchorType);
5458
}
5559

56-
5760
private static List<String> getListOfStringFromExtension(X509Certificate certificate, String extensionValue) throws IOException {
5861
List<String> extensionsStrings = new ArrayList<String>();
5962

6063
byte[] extension = certificate.getExtensionValue(extensionValue);
6164
if (extension != null) {
6265
// Read the First object
63-
ASN1InputStream asn1InputStream = new ASN1InputStream(extension);
64-
ASN1Primitive derObject = asn1InputStream.readObject();
66+
ASN1Primitive derObject = ASN1Primitive.fromByteArray(extension);
6567

6668
if (derObject != null && derObject instanceof DEROctetString) {
6769
DEROctetString derOctetString = (DEROctetString) derObject;
6870

6971
// Read the sub object which is expected to be a sequence
70-
ASN1InputStream derAsn1stream = new ASN1InputStream(derOctetString.getOctets());
71-
DLSequence dlSequence = (DLSequence) derAsn1stream.readObject();
72+
ASN1Primitive asn1Primitive1 = ASN1Primitive.fromByteArray(derOctetString.getOctets());
73+
DLSequence dlSequence = (DLSequence) asn1Primitive1;
7274

7375
// Enumerate all the objects in the sequence, we expect only one !
7476
Enumeration<?> seqEnum = dlSequence.getObjects();
@@ -79,15 +81,12 @@ private static List<String> getListOfStringFromExtension(X509Certificate certifi
7981
ASN1OctetString string = DEROctetString.getInstance(seqObj, false);
8082

8183
// Convert to a java String
82-
extensionsStrings.add(new String(string.getOctets()));
84+
extensionsStrings.add(new String(string.getOctets(), DEFAULT_CHARSET));
8385
}
84-
derAsn1stream.close();
86+
8587
LOG.debug("Anchor certificate types : '{}' for extension: {}", extensionsStrings.toString(), extensionValue);
8688
}
87-
88-
asn1InputStream.close();
8989
}
90-
9190
return extensionsStrings;
9291
}
9392

yoti-sdk-impl/src/test/java/com/yoti/api/client/spi/remote/SimpleActivityDetailsTest.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.yoti.api.client.Profile;
1414

1515
public class SimpleActivityDetailsTest {
16+
1617
private static final String USER_ID = "YmFkYWRhZGEtZGFkYWJhZGEK";
1718
private static final Profile USER_PROFILE = Mockito.mock(Profile.class);
1819
private static final Profile APP_PROFILE = Mockito.mock(Profile.class);
@@ -21,6 +22,7 @@ public class SimpleActivityDetailsTest {
2122
private static final byte[] RECEIPT_ID = { 1, 2, 3, 4, 5, 6, 7, 8 };
2223
private static final String RECEIPT_ID_STRING = Base64.toBase64String(RECEIPT_ID);
2324
private static final Date TIMESTAMP = new Date();
25+
private static final byte[] SOME_SELFIE_BYTES = "selfieTestVal".getBytes();
2426

2527
@Test(expected = IllegalArgumentException.class)
2628
public void shouldFailConstructionForNullRememberMeId() {
@@ -78,22 +80,22 @@ public void shouldReturnReceiptId() {
7880

7981
@Test
8082
public void shouldReturnBase64SelfieIfSelfieSet() {
81-
Attribute selfie = new Attribute("selfie", new JpegAttributeValue("selfieTestVal".getBytes()), null);
83+
Attribute selfie = new Attribute("selfie", new JpegAttributeValue(SOME_SELFIE_BYTES), null);
8284
SimpleProfile profile = new SimpleProfile(singletonList(selfie));
8385

84-
SimpleActivityDetails s = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
85-
String expected = "data:image/jpeg;base64," + Base64.toBase64String(s.getUserProfile().getSelfie().getContent());
86-
87-
assertEquals(expected, s.getBase64Selfie());
86+
SimpleActivityDetails result = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
87+
88+
String expected = "data:image/jpeg;base64," + Base64.toBase64String(SOME_SELFIE_BYTES);
89+
assertEquals(expected, result.getBase64Selfie());
8890
}
8991

9092
@Test
9193
public void shouldReturnBlankBase64SelfieIfSelfieNotSet() {
9294
Attribute familyName = new Attribute("family_name", "Smith", null);
9395
SimpleProfile profile = new SimpleProfile(singletonList(familyName));
9496

95-
SimpleActivityDetails s = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
97+
SimpleActivityDetails result = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
9698

97-
assertEquals("", s.getBase64Selfie());
99+
assertEquals("", result.getBase64Selfie());
98100
}
99101
}

yoti-sdk-spring-boot-auto-config/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ If you are using Maven, you need to add the following dependencies:
2626
If you are using Gradle, here is the dependency to add:
2727

2828
```
29-
compile group: 'com.yoti', name: 'yoti-sdk-spring-boot-auto-config', version: '1.4.1'
29+
compile group: 'com.yoti', name: 'yoti-sdk-spring-boot-auto-config', version: '1.5.0'
3030
```
3131

3232

yoti-sdk-spring-boot-auto-config/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
<dependency>
5454
<groupId>org.springframework.boot</groupId>
5555
<artifactId>spring-boot-autoconfigure</artifactId>
56-
<version>1.5.6.RELEASE</version>
56+
<version>1.5.10.RELEASE</version>
5757
<scope>provided</scope>
5858
</dependency>
5959

yoti-sdk-spring-boot-example/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Before you start, you'll need to create an Application in [Dashboard](https://ww
1616
<dependency>
1717
<groupId>com.yoti</groupId>
1818
<artifactId>yoti-sdk-impl</artifactId>
19-
<version>1.4.2</version>
19+
<version>1.5.0</version>
2020
</dependency>
2121
```
2222

yoti-sdk-spring-security/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ If you are using Maven, you need to add the following dependencies:
2525
<dependency>
2626
<groupId>com.yoti</groupId>
2727
<artifactId>yoti-sdk-spring-security</artifactId>
28-
<version>1.4.2</version>
28+
<version>1.5.0</version>
2929
</dependency>
3030
```
3131

3232
If you are using Gradle, here is the dependency to add:
3333

3434
```
35-
compile group: 'com.yoti', name: 'yoti-sdk-spring-security', version: '1.4.2'
35+
compile group: 'com.yoti', name: 'yoti-sdk-spring-security', version: '1.5.0'
3636
```
3737

3838
### Provide a `YotiClient` instance

0 commit comments

Comments
 (0)