-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
526b92e
commit 4012809
Showing
21 changed files
with
520 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Authentication | ||
|
||
Conductor supports integrated authentication using the [OpenID Connect](https://openid.net/connect/) protocol. | ||
|
||
By default, authentication is disabled. To enable it, | ||
* Set the `auth` environment variable to `'true'` | ||
* Set the `alg` environment variable to the signing algorithm (`RS256` or `ES256`) | ||
* Set the `publickey` variable to a Base64 encoded public key. | ||
|
||
If authentication is enabled then you need to include a signed [JWT bearer token](https://jwt.io/) along with every request. The is done by adding the `Authorization: Bearer <<token>>` header to each request. | ||
The token should be a valid JWT token that was signed with the corresponding private key to the public one in the environment variable. | ||
|
||
The token must also include a scope claim that indicate the level of access. The following scopes are used within Conductor. | ||
|
||
* `conductor:admin` - Adminstrative tasks. | ||
* `conductor:author` - Authoring of workflow definitions and steps. | ||
* `conductor:controller` - Starting, stopping, suspending and resuming workflows. | ||
* `conductor:viewer` - Querying the status of a workflow. | ||
|
||
A minimal JWT payload the include all the scopes would look as follows | ||
|
||
```json | ||
{ | ||
"scope": "conductor:admin conductor:author conductor:controller conductor:viewer" | ||
} | ||
``` | ||
|
||
Some authentication servers that support [OpenID Connect](https://openid.net/connect/) include | ||
|
||
* [Auth0](https://auth0.com/) - A cloud service | ||
* [Okta](https://www.okta.com/) - A cloud service | ||
* [Keycloak](https://github.com/keycloak/keycloak/) - Open source auth server | ||
* [Identity Server](https://identityserver.io/) - Open source auth server | ||
* [Dex](https://github.com/dexidp/dex) - Open source auth server | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authentication.JwtBearer; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.IdentityModel.Tokens; | ||
using Org.BouncyCastle.Security; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using System.Security.Cryptography; | ||
using System.Text.Encodings.Web; | ||
using System.Threading.Tasks; | ||
|
||
namespace Conductor.Auth | ||
{ | ||
public static class AuthExtensions | ||
{ | ||
|
||
public static AuthenticationBuilder AddJwtAuth(this AuthenticationBuilder builder, IConfiguration config) | ||
{ | ||
var signingKey = LoadKey(config); | ||
|
||
builder.AddJwtBearer(options => | ||
{ | ||
options.IncludeErrorDetails = true; | ||
options.RequireHttpsMetadata = false; | ||
|
||
options.TokenValidationParameters = new TokenValidationParameters | ||
{ | ||
ValidateIssuerSigningKey = true, | ||
IssuerSigningKey = signingKey, | ||
ValidateIssuer = false, | ||
ValidateAudience = false, | ||
RequireExpirationTime = false | ||
}; | ||
|
||
options.Validate(); | ||
}); | ||
|
||
return builder; | ||
} | ||
|
||
public static AuthenticationBuilder AddBypassAuth(this AuthenticationBuilder builder) | ||
{ | ||
var tokenHandler = new JwtSecurityTokenHandler(); | ||
var securityKey = new SymmetricSecurityKey(new byte[121]); | ||
var sc = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); | ||
|
||
var tokenDescriptor = new SecurityTokenDescriptor | ||
{ | ||
Subject = new ClaimsIdentity(new[] | ||
{ | ||
new Claim("scope", $"{Permissions.Admin} {Permissions.Author} {Permissions.Controller} {Permissions.Viewer}") | ||
}), | ||
SigningCredentials = sc, | ||
}; | ||
|
||
var token = tokenHandler.CreateToken(tokenDescriptor); | ||
var tokenString = tokenHandler.WriteToken(token); | ||
|
||
builder.AddJwtBearer(options => | ||
{ | ||
options.TokenValidationParameters = new TokenValidationParameters | ||
{ | ||
ValidateIssuerSigningKey = false, | ||
IssuerSigningKey = securityKey, | ||
ValidateIssuer = false, | ||
ValidateAudience = false, | ||
ValidateLifetime = false, | ||
}; | ||
options.RequireHttpsMetadata = false; | ||
options.Events = new JwtBearerEvents() | ||
{ | ||
OnMessageReceived = context => | ||
{ | ||
context.Token = tokenString; | ||
return Task.CompletedTask; | ||
} | ||
}; | ||
options.Validate(); | ||
}); | ||
|
||
return builder; | ||
} | ||
|
||
public static void AddPolicies(this IServiceCollection services) | ||
{ | ||
services.AddAuthorization(options => | ||
{ | ||
options.AddPolicy(Policies.Admin, policy => policy.RequireAssertion(context => context.User.Claims.Any(x => x.Type == "scope" && x.Value.Split(' ').Contains(Permissions.Admin)))); | ||
options.AddPolicy(Policies.Author, policy => policy.RequireAssertion(context => context.User.Claims.Any(x => x.Type == "scope" && x.Value.Split(' ').Contains(Permissions.Author)))); | ||
options.AddPolicy(Policies.Controller, policy => policy.RequireAssertion(context => context.User.Claims.Any(x => x.Type == "scope" && x.Value.Split(' ').Contains(Permissions.Controller)))); | ||
options.AddPolicy(Policies.Viewer, policy => policy.RequireAssertion(context => context.User.Claims.Any(x => x.Type == "scope" && x.Value.Split(' ').Contains(Permissions.Viewer)))); | ||
}); | ||
} | ||
|
||
private static SecurityKey LoadKey(IConfiguration config) | ||
{ | ||
var publicKeyBase64 = EnvironmentVariables.PublicKey; | ||
if (string.IsNullOrEmpty(publicKeyBase64)) | ||
publicKeyBase64 = config.GetSection("Auth").GetValue<string>("PublicKey"); | ||
var publicKey = Convert.FromBase64String(publicKeyBase64); | ||
|
||
var algName = EnvironmentVariables.Alg; | ||
if (string.IsNullOrEmpty(algName)) | ||
algName = config.GetSection("Auth").GetValue<string>("Algorithm"); | ||
|
||
if (algName.StartsWith("RS")) | ||
{ | ||
var rsa = RSA.Create(); | ||
try | ||
{ | ||
rsa.ImportSubjectPublicKeyInfo(publicKey, out _); | ||
} | ||
catch | ||
{ | ||
rsa.ImportRSAPublicKey(publicKey, out _); | ||
} | ||
return new RsaSecurityKey(rsa); | ||
} | ||
|
||
if (algName.StartsWith("ES")) | ||
{ | ||
var e1 = ECDsa.Create(); | ||
e1.ImportSubjectPublicKeyInfo(publicKey, out _); | ||
return new ECDsaSecurityKey(e1); | ||
} | ||
|
||
throw new ArgumentException("Only RSA and ECDSA algorithms are supported"); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Conductor.Auth | ||
{ | ||
public static class Permissions | ||
{ | ||
public const string Admin = "conductor:admin"; | ||
public const string Viewer = "conductor:viewer"; | ||
public const string Controller = "conductor:controller"; | ||
public const string Author = "conductor:author"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Conductor.Auth | ||
{ | ||
public static class Policies | ||
{ | ||
public const string Admin = "admin"; | ||
public const string Viewer = "viewer"; | ||
public const string Controller = "controller"; | ||
public const string Author = "author"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.