Skip to content

Commit

Permalink
Merge pull request #18 from YubicoLabs/next
Browse files Browse the repository at this point in the history
Merge Version 2.0 Release Candidate
  • Loading branch information
elukewalker authored Apr 11, 2022
2 parents 961bcb6 + 70593fd commit 509656d
Show file tree
Hide file tree
Showing 101 changed files with 41,173 additions and 31,484 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ xcuserdata/
*.xccheckout
*.xcscmblueprint
*.DS_Store
*.vscode

## Obj-C/Swift specific
*.hmap
Expand Down
61 changes: 32 additions & 29 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
== Version 2.0.0 RC ==

- Updated look and feel of UI
- Attestation data now displayed to the user (if they are using a YubiKey)
- Added prompts to guide users when registering a Platform Authenticator
- Changed SV-PIN to U2F Password
- Code changes to include better error handling, linting, and migrated to TypeScript

== Version 1.0.0 ==

GA release

* Added Docker deployment
* Apache License 2.0
- Added Docker deployment
- Apache License 2.0

== Version 0.0.6 ==

Beta release

* Speed up recovery code generation and validation
* Internal variable naming standardization and cleanup
* Configure URL redirects for SPA

- Speed up recovery code generation and validation
- Internal variable naming standardization and cleanup
- Configure URL redirects for SPA

== Version 0.0.5 ==

Beta release

* Initial iOS app commit
* Code cleanup (remove magic numbers, internal variable naming, etc.)
* Update dependencies
* Add more sanity checks to scripts

- Initial iOS app commit
- Code cleanup (remove magic numbers, internal variable naming, etc.)
- Update dependencies
- Add more sanity checks to scripts

== Version 0.0.4 ==

Beta release

* Fixed cascading delete bug
* Updated packages/dependencies and removed unused packages/dependencies
* Added recovery code and SV-PIN validation, max attempts, and hashing
* Deployment script bugfixes

- Fixed cascading delete bug
- Updated packages/dependencies and removed unused packages/dependencies
- Added recovery code and SV-PIN validation, max attempts, and hashing
- Deployment script bugfixes

== Version 0.0.3 ==

Beta release

* Added release notes & license

- Added release notes & license

== Version 0.0.2 ==

Beta release

* Client-Side Discoverable Credential, a.k.a. Usernameless, WebAuthn credential registration and authentication
* Improved error handling
* Delete user account feature
* Scripted deployment of backend and frontend

- Client-Side Discoverable Credential, a.k.a. Usernameless, WebAuthn credential registration and authentication
- Improved error handling
- Delete user account feature
- Scripted deployment of backend and frontend

== Version 0.0.1 ==

Alpha release

* AWS Cognito Custom Auth identifier-first WebAuthn registration and login flow
* WebAuthn lifecycle management (add/edit/remove WebAuthn credentials)
* Server-Verified PIN feature for authenticators without user verification capability
* Account recovery backup codes
* AWS SAM backend deployment based on CloudFormation template
* AWS Amplify hosted react web app
- AWS Cognito Custom Auth identifier-first WebAuthn registration and login flow
- WebAuthn lifecycle management (add/edit/remove WebAuthn credentials)
- Server-Verified PIN feature for authenticators without user verification capability
- Account recovery backup codes
- AWS SAM backend deployment based on CloudFormation template
- AWS Amplify hosted react web app
38 changes: 20 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,69 @@
# Yubico WebAuthn Starter Kit

The WebAuthn Starter Kit is an Authentication and Authorization turnkey solution applying the best practices for strong authentication while providing ways to automate deployment of a serverless cloud-first solution that is repeatable, modularized, and scalable.
The WebAuthn Starter Kit is an Authentication and Authorization turnkey solution applying the best practices for strong authentication while providing ways to automate deployment of a serverless cloud-first solution that is repeatable, modularized, and scalable.

![WebAuthn Kit Architecture Diagram](./assets/architectural-diagram.svg)

## How it works 🔧 ##
## How it works 🔧

The starter kit solution utilizes Amazon Cognito User Pools as an identity provider with a custom User Pool Workflow consisting of four AWS Lambda functions, a WebAuthn Lambda function, and an Amazon API Gateway endpoint, providing registration, authentication, and authorization for an identifier-first type flow.
The starter kit solution utilizes Amazon Cognito User Pools as an identity provider with a custom User Pool Workflow consisting of four AWS Lambda functions, a WebAuthn Lambda function, and an Amazon API Gateway endpoint, providing registration, authentication, and authorization for an Adaptive Multi-Factor Authentication with WebAuthn type flow.

## Deliverable 📬 ##
## Deliverable 📬

The solution will be provided as an Amazon SAM template that includes the creation of a Amazon Cognito User Pool, coded AWS Lambda functions, an Amazon Aurora database, an Amazon API Gateway endpoint, and necessary permissions to create, execute, and delete these resources in your own AWS account.

## Documentation ##
## Documentation

Check out our [Yubico WebuAthn Starter Kit Documentation](https://developers.yubico.com/Developer_Program/WebAuthn_Starter_Kit/) for more detailed design, architecture overview, installation guide(s), and documented WebAuthn authentication flows.
Check out our [Yubico WebuAthn Starter Kit Documentation](https://developers.yubico.com/Developer_Program/WebAuthn_Starter_Kit/) for more detailed design, architecture overview, installation guide(s), and documented WebAuthn authentication flows.

## Backend Resources ##
## Backend Resources

These resources will be created, configured, and deployed in your own AWS environment using the provided [SAM template](https://github.com/YubicoLabs/WebAuthnKit/blob/master/backend/template.yaml). These services provide registration, authentication, WebAuthn Relying Party, and OPEN ID Connect provider solutions.

✅ One Amazon Cognito User Pool.
✅ One Amazon Cognito User Pool.

<details><summary>Cognito User Pools as an Identity Provider</summary><p>

## About Cognito User Pools ##
## About Cognito User Pools

Amazon Cognito User Pools is a full-featured user directory managed AWS service that handles user registration, authentication, and account recovery. Amazon Cognito user pools implements ID, Access, and Refresh Tokens as defined by the OpenID Connect (OIDC) open standard.

Note :book: : User Pools provided tokens can be used to obtain temporary AWS credentials—with permissions you define—to access other AWS services directly or resources through Amazon API Gateway using Amazon Cognito Federated Identities (Identity Pool).
Note :book: : User Pools provided tokens can be used to obtain temporary AWS credentials—with permissions you define—to access other AWS services directly or resources through Amazon API Gateway using Amazon Cognito Federated Identities (Identity Pool).

The WebAuthn Starter Kit relies on Cognito User Pools to store user information and handle the custom registration and authentication flow. The kit can be used to leverage Cognito Federated Identities (identity pool) for fine-grain user access to other AWS resources.

</p>
</details>
</p>

Four AWS Lambda Functions used as custom triggers with Cognito User Pool.
✅ Four AWS Lambda Functions used as custom triggers with Cognito User Pool.

One AWS Lambda Function [(Yubico Java WebAuthn Server Library)](https://github.com/Yubico/java-webauthn-server) as the WebAuthn Relying Party.
✅ One AWS Lambda Function [(Yubico Java WebAuthn Server Library)](https://github.com/Yubico/java-webauthn-server) as the WebAuthn Relying Party.

One Amazon RDS Database - Aurora Serverless (MySQL-compatible database used to store user credential attributes).
✅ One Amazon RDS Database - Aurora Serverless (MySQL-compatible database used to store user credential attributes).

One Amazon API Gateway as our RESTful API endpoint.
✅ One Amazon API Gateway as our RESTful API endpoint.

## Backend

Deploy the backend as outlined in [backend](./backend/README.md).

## Clients ##
## Clients

Once you build and deploy the backend, you can use one of the clients below to connect into the backend.

[Web Client (React)](https://github.com/YubicoLabs/WebAuthnKit/tree/master/clients/web/react)

[iOS Client (Swift)](https://github.com/YubicoLabs/WebAuthnKit/tree/master/clients/iOS)

## Cost Considerations ##
## Cost Considerations

We have done our best to reduce the cost of running the Yubico WebAuthn Starter Kit on AWS, however, you are responsible the AWS service fees while running the WebAuthn Starter Kit reference deployment.

The WebAuthn Starter Kit utilizes an AWS SAM template for quick deployment. This template includes configuration parameters that you can customize to fit your needs and budget. Some of these settings, such as RDS Aurora database, affect the cost of deployment. For cost estimates, see the pricing pages for each AWS service used.

Cost Analysis: After you deploy the WebAuthn Starter Kit to your AWS environment, you can create a [AWS Cost and Usage Report](https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html) to track costs associated with this deployment. This report will deliver billing metrics (cost estimates based on usage) to an Amazon S3 bucket in your own account.

## License Summary ##
## License Summary

This project is licensed under [Apache License 2.0](https://github.com/YubicoLabs/WebAuthnKit/blob/main/COPYING).
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ var constraints = {
}
}
};
const authSelectorResolve = {
"PLATFORM": "platform",
"CROSS_PLATFORM": "cross-platform"
};

// Using npmjs.com/package/data-api-client package for accessing an Aurora Serverless Database with Data API enabled
const data = require('data-api-client')({
Expand Down Expand Up @@ -132,6 +136,7 @@ async function getCreateCredentialsOptions(event, creds) {
startRegisterPayload.publicKeyCredentialCreationOptions.challenge = startRegisterPayload.publicKeyCredentialCreationOptions.challenge.base64;
startRegisterPayload.publicKeyCredentialCreationOptions.attestation = startRegisterPayload.publicKeyCredentialCreationOptions.attestation.toLowerCase();
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.userVerification = startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.userVerification.toLowerCase();
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.authenticatorAttachment = authSelectorResolve[startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.authenticatorAttachment];
startRegisterPayload.publicKeyCredentialCreationOptions.pubKeyCredParams = startRegisterPayload.publicKeyCredentialCreationOptions.pubKeyCredParams.map( (cred) => {
cred.type = cred.type.toLowerCase().replace('_','-');
cred.alg = coseLookup[cred.alg];
Expand Down
20 changes: 19 additions & 1 deletion backend/lambda-functions/FIDO2KitAPI/FIDO2KitAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ const constraints = {
};
const saltRounds = 5;

const authSelectorResolve = {
"PLATFORM": "platform",
"CROSS_PLATFORM": "cross-platform"
};


exports.handler = async (event, context) => {

Expand Down Expand Up @@ -297,6 +302,7 @@ async function startRegisterFIDO2Credential(profile, body, uid) {
"displayName": profile.username,
"credentialNickname": jsonBody.nickname,
"requireResidentKey": jsonBody.requireResidentKey,
"requireAuthenticatorAttachment": jsonBody.requireAuthenticatorAttachment,
"uid": uid
});
console.log("startRegistration request payload: "+payload);
Expand All @@ -321,6 +327,12 @@ async function startRegisterFIDO2Credential(profile, body, uid) {
startRegisterPayload.publicKeyCredentialCreationOptions.challenge = startRegisterPayload.publicKeyCredentialCreationOptions.challenge.base64;
startRegisterPayload.publicKeyCredentialCreationOptions.attestation = startRegisterPayload.publicKeyCredentialCreationOptions.attestation.toLowerCase();
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.userVerification = startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.userVerification.toLowerCase();
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.residentKey = startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.residentKey.toLowerCase();
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.requireResidentKey = false;
if(startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.residentKey === "required") {
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.requireResidentKey = true;
}
startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.authenticatorAttachment = authSelectorResolve[startRegisterPayload.publicKeyCredentialCreationOptions.authenticatorSelection.authenticatorAttachment];
startRegisterPayload.publicKeyCredentialCreationOptions.pubKeyCredParams = startRegisterPayload.publicKeyCredentialCreationOptions.pubKeyCredParams.map( (cred) => {
cred.type = cred.type.toLowerCase().replace('_','-');
cred.alg = coseLookup[cred.alg];
Expand Down Expand Up @@ -376,7 +388,7 @@ async function finishRegisterFIDO2Credential(userName, body) {
console.log("isPinVerified: ", isPinVerified);

if(!isPinVerified){
let err = "Incorrect pin.";
let err = "The provided PIN was incorrect. Please attempt again.";
console.log("error"+ err);
return error(err);
}
Expand Down Expand Up @@ -424,6 +436,12 @@ async function finishRegisterFIDO2Credential(userName, body) {
console.log("response: ", response);
let payload = JSON.parse(response.Payload);
console.log("response payload: ", payload);

// exceptions will have a message property
if(payload.message !== undefined) {
console.log("error: "+ payload.message);
return error(new Error(payload.message));
}

return ok(payload);
} catch (err) {
Expand Down
6 changes: 6 additions & 0 deletions backend/lambda-functions/JavaWebAuthnLib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@
<version>2.17.1</version>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) 2018, Yubico AB
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.yubico.webauthn.attestation.resolver;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.yubico.webauthn.attestation.TrustResolver;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
* Resolves a metadata object whose associated certificate has signed the argument certificate, or
* is equal to the argument certificate.
*/
public class SimpleTrustResolverWithEquality implements TrustResolver {

private final SimpleTrustResolver subresolver;
private final Multimap<String, X509Certificate> trustedCerts = ArrayListMultimap.create();

public SimpleTrustResolverWithEquality(Collection<X509Certificate> trustedCertificates) {
subresolver = new SimpleTrustResolver(trustedCertificates);

for (X509Certificate cert : trustedCertificates) {
trustedCerts.put(cert.getSubjectDN().getName(), cert);
}
}

@Override
public Optional<X509Certificate> resolveTrustAnchor(
X509Certificate attestationCertificate, List<X509Certificate> caCertificateChain) {
Optional<X509Certificate> subResult =
subresolver.resolveTrustAnchor(attestationCertificate, caCertificateChain);

if (subResult.isPresent()) {
return subResult;
} else {
for (X509Certificate cert :
trustedCerts.get(attestationCertificate.getSubjectDN().getName())) {
if (cert.equals(attestationCertificate)) {
return Optional.of(cert);
}
}

return Optional.empty();
}
}
}
Loading

0 comments on commit 509656d

Please sign in to comment.