Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] "Sign in With Apple" provider #318

Draft
wants to merge 19 commits into
base: dev
from

Conversation

2 participants
@martincostello
Copy link
Member

commented Jun 6, 2019

Adds a Sign In with Apple provider based on currently available information.

Reference sources were:

Relates to #314.

All the provider does at present is set the NameIdentifier claim in the claims principal to the value of the subject of the JWT returned from the token endpoint.

No information about a user information endpoint is yet available, but the docs suggest this will come at a later point:

access_token string
(Reserved for future use) A token used to access allowed data. Currently, no data set has been defined for access.

@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 8, 2019

Working demo now available at https://signinwithapple.azurewebsites.net/

@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 9, 2019

Note that in Azure App Service, you have to set WEBSITE_LOAD_USER_PROFILE=1 to be able to load the private key from the .p8 file.

martincostello added some commits Jun 6, 2019

Basic Apple provider
Add a very basic Sign In with Apple provider based on currently available information.
Implement Apple provider
Fully implement the provider for Sign In with Apple based on current available functionality.
Enable Sign In with Apple
Enable Sign In with Apple in the MVC sample app without hard-coding secrets.
Update tests
Update the tests for the updated provider implementation.
Fix incorrect test method name.
Enable token lifetime validation
Enable the validation of token lifetimes.
Add null annotations
Add [NotNull] attributes to relevant methods.
Improve exception handling
Pre-validate the ID token has a value.
Change catch clause to improve logging.
Extend integration tests
Extend the integration tests for additional scenarios such as no validation, invalid tokens and using a configured client secret.
Move expiry period to options
Move the configured lifetime for generated client secrets to the options class.
Add ClientSecretExpiresAfter validation
Add validation for the value of ClientSecretExpiresAfter.
Add tests for options validation
Add unit tests for options validation.
Improve exception type.
Fix incorrect if condition that meant not all values were validated correctly.
Add unit tests for client secret
Add unit tests for the generated client secret's format.
Make KeyId required
Make the KeyId option required if GenerateClientSecret is true.
Fix test
Fix the expiry not being set.

@martincostello martincostello force-pushed the martincostello:Sign-In-With-Apple branch from 39e8258 to 2a0bc93 Jun 9, 2019

@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 9, 2019

Works on Windows but fails on macOS and Linux. Needs refactoring to account for CngKey.Import() being Windows-specific: dotnet/corefx#18733 (comment).

martincostello added some commits Jun 9, 2019

Fix Linux and macOS secret generation
Work around platform differences between Windows and Linux/macOS by supporting .p12/.pfx certificates for Linux/macOS and using p8 for Windows.
.NET Core 3.0 adds support for .p8 on both platforms.
Add password option for pfx files
Add an option for specifying a password for PFX files.
Add a test private key that has a password for use on macOS.
@kinosang

This comment has been minimized.

Copy link
Contributor

commented Jun 9, 2019

Have you try with X509Certificate2? It can parse pkcs8 or pkcs12, and provide RsaPrivateKey and RsaPublicKey.

Fix flaky test
Fix flaky test by setting the expiry to 2 seconds to eliminate rounding issues.
@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 9, 2019

Yeah, I found a comment that lead me to X509Certificate2 for if the private key is in .pfx format.

private ECDsa CreateAlgorithm(byte[] keyBlob, string password)
{
// This becomes xplat in .NET Core 3.0: https://github.com/dotnet/corefx/pull/30271
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
CreateAlgorithmWindows(keyBlob) :
CreateAlgorithmLinuxOrMac(keyBlob, password);
}
private ECDsa CreateAlgorithmLinuxOrMac(byte[] keyBlob, string password)
{
// Does not support .p8 files in .NET Core 2.x as-per https://github.com/dotnet/corefx/issues/18733#issuecomment-296723615
// Unlike Linux, macOS does not support empty passwords for .pfx files.
using (var cert = new X509Certificate2(keyBlob, password))
{
return cert.GetECDsaPrivateKey();
}
}
private ECDsa CreateAlgorithmWindows(byte[] keyBlob)
{
// Only Windows supports .p8 files in .NET Core 2.0 as-per https://github.com/dotnet/corefx/issues/18733
using (var privateKey = CngKey.Import(keyBlob, CngKeyBlobFormat.Pkcs8PrivateBlob))
{
return new ECDsaCng(privateKey) { HashAlgorithm = CngAlgorithm.Sha256 };
}
}

For now I've forked the implementation so Windows supports .p8 (as that's the format Apple provide the user with so is the least-work to integrate), but Linux and macOS only support .pfx so the user needs to extract the .cer from the .p8 and then combine them into a .pfx using OpenSSL.

Now the tests pass: https://travis-ci.com/martincostello/AspNet.Security.OAuth.Providers/builds/114862873

.NET Core 3.0 supports .p8 on all three platforms, so the implementation can be simplified for 3.0 and the #280 branch, but I imagine if the community want to use this when Apple release the product, they'd rather have the option of 2.x or 3.0, rather than having to port their app to 3.0 just to be able to use Sign In with Apple.

@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 9, 2019

ASP.NET Core 3.0 branch of the Apple provider is here.

The code is simpler and supports .p8 private keys on all platforms: ee4a2f7

Tests: https://travis-ci.com/martincostello/AspNet.Security.OAuth.Providers/builds/114865903

@martincostello martincostello self-assigned this Jun 9, 2019

martincostello added some commits Jun 9, 2019

Add UsePrivateKey() method
Add UsePrivateKey() extension method that configures a private key file to use to auto-generate client secrets.
Bump System.IdentityModel.Tokens.Jwt
Bump System.IdentityModel.Tokens.Jwt to 5.3.0 to ensure that incompatibility with .NET Standard 1.4 doesn't affect consumers.
@martincostello

This comment has been minimized.

Copy link
Member Author

commented Jun 10, 2019

I've done a blog post about the implementation here: https://blog.martincostello.com/sign-in-with-apple-prototype-for-aspnet-core/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.