Skip to content

Commit

Permalink
feat: add Jupiter+Weld+Mockito+Extension to Fido2 (#3875)
Browse files Browse the repository at this point in the history
  • Loading branch information
yurem committed Feb 17, 2023
1 parent 83183c0 commit 0152435
Show file tree
Hide file tree
Showing 16 changed files with 578 additions and 32 deletions.
37 changes: 37 additions & 0 deletions jans-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,44 @@
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-junit5</artifactId>
<version>4.0.0.Final</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.1.1</version>
<scope>test</scope>
</dependency>

<!-- java compiler lib -->
<dependency>
<groupId>net.openhft</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,25 @@

package io.jans.service.net;

import io.jans.net.InetAddressUtility;
import io.jans.util.StringHelper;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;

import org.slf4j.Logger;

import io.jans.net.InetAddressUtility;
import io.jans.util.StringHelper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;

/**
* Network service
*
* @author Yuriy Movchan Date: 04/28/2016
*/
@ApplicationScoped
@Named
public class NetworkService implements Serializable {

private static final long serialVersionUID = -1393318600428448743L;
Expand Down
17 changes: 17 additions & 0 deletions jans-fido2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
Expand Down Expand Up @@ -175,6 +180,18 @@
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
Expand Down
41 changes: 41 additions & 0 deletions jans-fido2/server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
<includes>
<include>**/*.json</include>
<include>**/*.xml</include>
<include>**/keys/**/*.*</include>
<include>**/*.properties</include>
</includes>
</testResource>
</testResources>
Expand Down Expand Up @@ -90,6 +92,18 @@
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
</dependencies>
</plugin>
-->
</plugins>
</build>

Expand Down Expand Up @@ -149,6 +163,33 @@
<artifactId>kerby-asn1</artifactId>
<version>2.0.1</version>
</dependency>

<!-- Test -->
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<reporting>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,24 @@ public class AttestationSuperGluuController {
* "appId":"https://yurem-emerging-pig.gluu.info/identity/authcode.htm","version":"U2F_V2"}]}
*/
public JsonNode startRegistration(String userName, String appId, String sessionId, String enrollmentCode) {
boolean oneStep = StringHelper.isEmpty(userName);
ObjectNode params = buildFido2AttestationStartResponse(userName, appId, sessionId);

ObjectNode result = attestationService.options(params);

// Build start registration response
ObjectNode superGluuResult = dataMapperService.createObjectNode();
ArrayNode registerRequests = superGluuResult.putArray("registerRequests");

result.put("appId", appId);
registerRequests.add(result);

result.put("version", "U2F_V2");

return superGluuResult;
}

public ObjectNode buildFido2AttestationStartResponse(String userName, String appId, String sessionId) {
boolean oneStep = StringHelper.isEmpty(userName);

boolean valid = userSessionIdService.isValidSessionId(sessionId, userName);
if (!valid) {
Expand All @@ -130,20 +147,8 @@ public JsonNode startRegistration(String userName, String appId, String sessionI
params.put("attestation", "direct");

log.debug("Prepared U2F_V2 attestation options request: {}", params.toString());

ObjectNode result = attestationService.options(params);

// Build start registration response
ObjectNode superGluuResult = dataMapperService.createObjectNode();
ArrayNode registerRequests = superGluuResult.putArray("registerRequests");

result.put("appId", appId);
registerRequests.add(result);

result.put("version", "U2F_V2");

return superGluuResult;
}
return params;
}

/* Example for one_step:
* - request:
Expand Down Expand Up @@ -189,14 +194,31 @@ public JsonNode startRegistration(String userName, String appId, String sessionI
*
*/
public JsonNode finishRegistration(String userName, String registerResponseString) {
RegisterResponse registerResponse;
RegisterResponse registerResponse = parseRegisterResponse(registerResponseString);

ObjectNode params = buildFido2AttestationVerifyResponse(userName, registerResponse);

ObjectNode result = attestationService.verify(params);

result.put("status", "success");
result.put("challenge", registerResponse.getClientData().getChallenge());

return result;
}

public RegisterResponse parseRegisterResponse(String registerResponseString) {
RegisterResponse registerResponse;
try {
registerResponse = dataMapperService.readValue(registerResponseString, RegisterResponse.class);
} catch (IOException ex) {
throw new Fido2RpRuntimeException("Failed to parse options attestation request", ex);
}

if (!ArrayUtils.contains(RawRegistrationService.SUPPORTED_REGISTER_TYPES, registerResponse.getClientData().getTyp())) {
return registerResponse;
}

public ObjectNode buildFido2AttestationVerifyResponse(String userName, RegisterResponse registerResponse) {
if (!ArrayUtils.contains(RawRegistrationService.SUPPORTED_REGISTER_TYPES, registerResponse.getClientData().getTyp())) {
throw new Fido2RuntimeException("Invalid options attestation request type");
}

Expand Down Expand Up @@ -250,14 +272,8 @@ public JsonNode finishRegistration(String userName, String registerResponseStrin
}

log.debug("Prepared U2F_V2 attestation verify request: {}", params.toString());

ObjectNode result = attestationService.verify(params);

result.put("status", "success");
result.put("challenge", registerResponse.getClientData().getChallenge());

return result;
}
return params;
}

private byte[] generateAuthData(ClientData clientData, RawRegisterResponse rawRegisterResponse) throws IOException {
byte[] rpIdHash = digestService.hashSha256(clientData.getOrigin());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text.
*
* Copyright (c) 2023, Janssen Project
*/

package io.jans.fido2.service;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import org.apache.commons.io.FileUtils;
import org.jboss.weld.junit5.auto.AddPackages;
import org.jboss.weld.junit5.auto.WeldJunit5AutoExtension;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import io.jans.as.model.util.SecurityProviderUtility;
import jakarta.inject.Inject;

/**
* @author Yuriy Movchan
* @version 0.1, 17/02/2023
*/
@ExtendWith(WeldJunit5AutoExtension.class)
@AddPackages(io.jans.service.util.Resources.class)
public class KeySignatureVerifierTest {

@Inject
Base64Service base64Service;

@BeforeAll
public static void beforeAll() {
SecurityProviderUtility.installBCProvider();
}

/*
* openssl ecparam -name secp256r1 -genkey -noout -out private.key
* openssl ec -in private.key -pubout -out public.pem
* echo -n "test" > data.txt
*
* openssl dgst -sha256 -sign private.key data.txt | openssl enc -base64 > signature.txt
*/
@Test
public void testSHA256withECDSASignature() throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, SignatureException {
String key = FileUtils.readFileToString(new File("./target/test-classes/keys/secp256r1/public.pem"), StandardCharsets.UTF_8);
String publicKeyPEM = key.replace("-----BEGIN PUBLIC KEY-----", "").replaceAll(System.lineSeparator(), "").replace("-----END PUBLIC KEY-----", "");

KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(base64Service.decode(publicKeyPEM));
PublicKey publicKey = keyFactory.generatePublic(keySpec);

byte[] signature = base64Service.decode(FileUtils.readFileToString(new File("./target/test-classes/keys/secp256r1/signature.txt"),
StandardCharsets.UTF_8).replaceAll(System.lineSeparator(), ""));
byte[] signedBytes = FileUtils.readFileToString(new File("./target/test-classes/keys/secp256r1/data.txt"), StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);

Signature ecdsaSignature = Signature.getInstance("SHA256withECDSA", "BC");
ecdsaSignature.initVerify(publicKey);
ecdsaSignature.update(signedBytes);

boolean isValid = ecdsaSignature.verify(signature);
assertTrue(isValid);
}

}
Loading

0 comments on commit 0152435

Please sign in to comment.