Skip to content

Commit

Permalink
Merge pull request #57 from getyoti/API-476
Browse files Browse the repository at this point in the history
API-476: Final tidy up
  • Loading branch information
bucky-boy authored Apr 19, 2018
2 parents 25f8062 + 3d98bcd commit 23f87ef
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 94 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ If you are using Maven, you need to add the following dependency:
<dependency>
<groupId>com.yoti</groupId>
<artifactId>yoti-sdk-impl</artifactId>
<version>1.4.2</version>
<version>1.5.0</version>
</dependency>
```

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,53 @@
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yoti.api.client.Attribute;
import com.yoti.api.client.spi.remote.proto.AttrProto;
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;
import com.yoti.api.client.spi.remote.proto.ContentTypeProto.ContentType;
import com.yoti.api.client.spi.remote.util.AnchorCertificateParser;
import com.yoti.api.client.spi.remote.util.AnchorType;
import com.yoti.api.client.spi.remote.util.AnchorCertificateParser.AnchorVerifierSourceData;
import com.yoti.api.client.spi.remote.util.AnchorType;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AttributeConverter {

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


public static Attribute convertAttribute(AttrProto.Attribute attribute) throws ParseException, IOException{
if (ContentType.STRING.equals(attribute.getContentType())) {
return new com.yoti.api.client.Attribute(attribute.getName(),
attribute.getValue().toString(DEFAULT_CHARSET),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
} else if (ContentType.DATE.equals(attribute.getContentType())) {
return new com.yoti.api.client.Attribute(attribute.getName(),
DateAttributeValue.parseFrom(attribute.getValue().toByteArray()),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
} else if (ContentType.JPEG.equals(attribute.getContentType())) {
return new com.yoti.api.client.Attribute(attribute.getName(),
new JpegAttributeValue(attribute.getValue().toByteArray()),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
} else if (ContentType.PNG.equals(attribute.getContentType())) {
return new com.yoti.api.client.Attribute(attribute.getName(),
new PngAttributeValue(attribute.getValue().toByteArray()),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
} else if (ContentType.JSON.equals(attribute.getContentType())) {
return new com.yoti.api.client.Attribute(attribute.getName(),
JSON_MAPPER.readValue(attribute.getValue().toString(DEFAULT_CHARSET), Map.class),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
public static Attribute convertAttribute(com.yoti.api.client.spi.remote.proto.AttrProto.Attribute attribute) throws ParseException, IOException {
switch (attribute.getContentType()) {
case STRING:
return attributeWithMetadata(attribute, attribute.getValue().toString(DEFAULT_CHARSET));
case DATE:
return attributeWithMetadata(attribute, DateAttributeValue.parseFrom(attribute.getValue().toByteArray()));
case JPEG:
return attributeWithMetadata(attribute, new JpegAttributeValue(attribute.getValue().toByteArray()));
case PNG:
return attributeWithMetadata(attribute, new PngAttributeValue(attribute.getValue().toByteArray()));
case JSON:
return attributeWithMetadata(attribute, JSON_MAPPER.readValue(attribute.getValue().toString(DEFAULT_CHARSET), Map.class));
default:
LOG.error("Unknown type {} for attribute {}", attribute.getContentType(), attribute.getName());
return attributeWithMetadata(attribute, attribute.getValue().toString(DEFAULT_CHARSET));
}
}

LOG.error("Unknown type {} for attribute {}", attribute.getContentType(), attribute.getName());
return new com.yoti.api.client.Attribute(attribute.getName(),
attribute.getValue().toString(DEFAULT_CHARSET),
extractMetadata(attribute, AnchorType.SOURCE),
extractMetadata(attribute, AnchorType.VERIFIER));
private static Attribute attributeWithMetadata(AttrProto.Attribute attribute, Object value) {
return new Attribute(attribute.getName(), value, extractMetadata(attribute, AnchorType.SOURCE), extractMetadata(attribute, AnchorType.VERIFIER));
}

private static Set<String> extractMetadata(AttrProto.Attribute attribute, AnchorType anchorType) {
Set<String> entries = new HashSet<String>();
for (Anchor anchor : attribute.getAnchorsList()) {
AnchorVerifierSourceData anchorData = AnchorCertificateParser.getTypesFromAnchor(anchor);
if(anchorData.getType().equals(anchorType)) {
if (anchorData.getType().equals(anchorType)) {
entries.addAll(anchorData.getEntries());
}
}
return entries;
}


}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.yoti.api.client.spi.remote;

import static javax.crypto.Cipher.DECRYPT_MODE;

import static com.yoti.api.client.spi.remote.call.YotiConstants.ASYMMETRIC_CIPHER;
import static com.yoti.api.client.spi.remote.call.YotiConstants.BOUNCY_CASTLE_PROVIDER;
import static com.yoti.api.client.spi.remote.call.YotiConstants.DEFAULT_CHARSET;
import static com.yoti.api.client.spi.remote.call.YotiConstants.SYMMETRIC_CIPHER;
import static com.yoti.api.client.spi.remote.util.Validation.notNull;
import static javax.crypto.Cipher.DECRYPT_MODE;

import java.io.BufferedReader;
import java.io.IOException;
Expand All @@ -27,18 +28,10 @@
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.yoti.api.client.ActivityDetails;
import com.yoti.api.client.ActivityFailureException;
import com.yoti.api.client.AmlException;
import com.yoti.api.client.Attribute;
import com.yoti.api.client.InitialisationException;
import com.yoti.api.client.KeyPairSource;
import com.yoti.api.client.KeyPairSource.StreamVisitor;
Expand All @@ -50,10 +43,19 @@
import com.yoti.api.client.spi.remote.call.ProfileService;
import com.yoti.api.client.spi.remote.call.Receipt;
import com.yoti.api.client.spi.remote.call.aml.RemoteAmlService;
import com.yoti.api.client.spi.remote.proto.AttrProto.Attribute;
import com.yoti.api.client.spi.remote.proto.AttrProto;
import com.yoti.api.client.spi.remote.proto.AttributeListProto.AttributeList;
import com.yoti.api.client.spi.remote.proto.EncryptedDataProto.EncryptedData;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* YotiClient talking to the Yoti Connect API remotely.
*/
Expand Down Expand Up @@ -140,7 +142,7 @@ private void validateReceipt(Receipt receipt) throws ActivityFailureException {
}

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

private List<com.yoti.api.client.Attribute> parseProfile(byte[] profileData) throws ProfileException {
List<com.yoti.api.client.Attribute> attributeList = null;
private List<Attribute> parseProfile(byte[] profileData) throws ProfileException {
try {
AttributeList message = AttributeList.parseFrom(profileData);
attributeList = parseAttributes(message);
List<Attribute> attributeList = parseAttributes(message);
LOG.debug("{} attribute(s) parsed", attributeList.size());
return attributeList;
} catch (InvalidProtocolBufferException e) {
throw new ProfileException("Cannot parse profile data", e);
}
return attributeList;
}

private List<com.yoti.api.client.Attribute> parseAttributes(AttributeList message) {
List<com.yoti.api.client.Attribute> parsedAttributes = new ArrayList<com.yoti.api.client.Attribute>();
for (Attribute attribute : message.getAttributesList()) {
private List<Attribute> parseAttributes(AttributeList message) {
List<Attribute> parsedAttributes = new ArrayList<Attribute>();
for (AttrProto.Attribute attribute : message.getAttributesList()) {
try {
com.yoti.api.client.Attribute parsedAttribute = AttributeConverter.convertAttribute(attribute);
if (parsedAttribute != null) {
parsedAttributes.add(parsedAttribute);
}
parsedAttributes.add(AttributeConverter.convertAttribute(attribute));
} catch (IOException e) {
LOG.info("Cannot decode value for attribute {}", attribute.getName());
} catch (ParseException e) {
Expand All @@ -191,7 +189,7 @@ private List<com.yoti.api.client.Attribute> parseAttributes(AttributeList messag
}


private Profile createProfile(List<com.yoti.api.client.Attribute> attributeList) {
private Profile createProfile(List<Attribute> attributeList) {
return new SimpleProfile(attributeList);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.yoti.api.client.spi.remote.util;

import static com.yoti.api.client.spi.remote.call.YotiConstants.DEFAULT_CHARSET;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
Expand All @@ -10,7 +13,9 @@
import java.util.List;
import java.util.Set;

import org.bouncycastle.asn1.ASN1InputStream;
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;

import com.google.protobuf.ByteString;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1TaggedObject;
Expand All @@ -19,13 +24,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.protobuf.ByteString;
import com.yoti.api.client.spi.remote.proto.AttrProto.Anchor;

public class AnchorCertificateParser {

private static final Logger LOG = LoggerFactory.getLogger(AnchorCertificateParser.class);


public static AnchorVerifierSourceData getTypesFromAnchor(Anchor anchor) {
Set<String> types = new HashSet<String>(anchor.getOriginServerCertsCount());
AnchorType anchorType = AnchorType.UNKNOWN;
Expand All @@ -46,29 +48,29 @@ public static AnchorVerifierSourceData getTypesFromAnchor(Anchor anchor) {
}
types.addAll(extensions);
}
} catch (Exception e) {
} catch (IOException e) {
LOG.warn("Could not extract anchor type from certificate.", e);
} catch (CertificateException e) {
LOG.warn("Could not extract anchor type from certificate.", e);
}

return new AnchorVerifierSourceData(types, anchorType);
}


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

byte[] extension = certificate.getExtensionValue(extensionValue);
if (extension != null) {
// Read the First object
ASN1InputStream asn1InputStream = new ASN1InputStream(extension);
ASN1Primitive derObject = asn1InputStream.readObject();
ASN1Primitive derObject = ASN1Primitive.fromByteArray(extension);

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

// Read the sub object which is expected to be a sequence
ASN1InputStream derAsn1stream = new ASN1InputStream(derOctetString.getOctets());
DLSequence dlSequence = (DLSequence) derAsn1stream.readObject();
ASN1Primitive asn1Primitive1 = ASN1Primitive.fromByteArray(derOctetString.getOctets());
DLSequence dlSequence = (DLSequence) asn1Primitive1;

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

// Convert to a java String
extensionsStrings.add(new String(string.getOctets()));
extensionsStrings.add(new String(string.getOctets(), DEFAULT_CHARSET));
}
derAsn1stream.close();

LOG.debug("Anchor certificate types : '{}' for extension: {}", extensionsStrings.toString(), extensionValue);
}

asn1InputStream.close();
}

return extensionsStrings;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.yoti.api.client.Profile;

public class SimpleActivityDetailsTest {

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

@Test(expected = IllegalArgumentException.class)
public void shouldFailConstructionForNullRememberMeId() {
Expand Down Expand Up @@ -78,22 +80,22 @@ public void shouldReturnReceiptId() {

@Test
public void shouldReturnBase64SelfieIfSelfieSet() {
Attribute selfie = new Attribute("selfie", new JpegAttributeValue("selfieTestVal".getBytes()), null);
Attribute selfie = new Attribute("selfie", new JpegAttributeValue(SOME_SELFIE_BYTES), null);
SimpleProfile profile = new SimpleProfile(singletonList(selfie));

SimpleActivityDetails s = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
String expected = "data:image/jpeg;base64," + Base64.toBase64String(s.getUserProfile().getSelfie().getContent());

assertEquals(expected, s.getBase64Selfie());
SimpleActivityDetails result = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);

String expected = "data:image/jpeg;base64," + Base64.toBase64String(SOME_SELFIE_BYTES);
assertEquals(expected, result.getBase64Selfie());
}

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

SimpleActivityDetails s = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);
SimpleActivityDetails result = new SimpleActivityDetails(USER_ID, profile, APP_PROFILE, TIMESTAMP, RECEIPT_ID);

assertEquals("", s.getBase64Selfie());
assertEquals("", result.getBase64Selfie());
}
}
2 changes: 1 addition & 1 deletion yoti-sdk-spring-boot-auto-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ If you are using Maven, you need to add the following dependencies:
If you are using Gradle, here is the dependency to add:

```
compile group: 'com.yoti', name: 'yoti-sdk-spring-boot-auto-config', version: '1.4.1'
compile group: 'com.yoti', name: 'yoti-sdk-spring-boot-auto-config', version: '1.5.0'
```


Expand Down
2 changes: 1 addition & 1 deletion yoti-sdk-spring-boot-auto-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.5.6.RELEASE</version>
<version>1.5.10.RELEASE</version>
<scope>provided</scope>
</dependency>

Expand Down
2 changes: 1 addition & 1 deletion yoti-sdk-spring-boot-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Before you start, you'll need to create an Application in [Dashboard](https://ww
<dependency>
<groupId>com.yoti</groupId>
<artifactId>yoti-sdk-impl</artifactId>
<version>1.4.2</version>
<version>1.5.0</version>
</dependency>
```

Expand Down
4 changes: 2 additions & 2 deletions yoti-sdk-spring-security/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ If you are using Maven, you need to add the following dependencies:
<dependency>
<groupId>com.yoti</groupId>
<artifactId>yoti-sdk-spring-security</artifactId>
<version>1.4.2</version>
<version>1.5.0</version>
</dependency>
```

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

```
compile group: 'com.yoti', name: 'yoti-sdk-spring-security', version: '1.4.2'
compile group: 'com.yoti', name: 'yoti-sdk-spring-security', version: '1.5.0'
```

### Provide a `YotiClient` instance
Expand Down
Loading

0 comments on commit 23f87ef

Please sign in to comment.