From b804a114e1eefdb80a204bcf66b42570ae1e4483 Mon Sep 17 00:00:00 2001 From: Erich Barnstedt Date: Tue, 9 May 2017 11:35:51 +0200 Subject: [PATCH] Remove OAuth2 for now (this is work in progress) and auto-accepting untrusted certs. --- SampleApplications/Samples/GDS/App.config | 4 +- .../Samples/GDS/AuthorizationService.cs | 449 ------------------ .../Samples/GDS/GlobalDiscoveryServer.csproj | 54 --- .../GDS/GlobalDiscoveryServerServer.cs | Bin 50134 -> 49182 bytes SampleApplications/Samples/GDS/Program.cs | 16 - SampleApplications/Samples/GDS/SelfHost.cs | 47 -- .../Samples/GDS/packages.config | 13 - 7 files changed, 2 insertions(+), 581 deletions(-) delete mode 100644 SampleApplications/Samples/GDS/AuthorizationService.cs delete mode 100644 SampleApplications/Samples/GDS/SelfHost.cs diff --git a/SampleApplications/Samples/GDS/App.config b/SampleApplications/Samples/GDS/App.config index 1b397f1b74..4fbd7a2c74 100644 --- a/SampleApplications/Samples/GDS/App.config +++ b/SampleApplications/Samples/GDS/App.config @@ -3,8 +3,8 @@
- - + + diff --git a/SampleApplications/Samples/GDS/AuthorizationService.cs b/SampleApplications/Samples/GDS/AuthorizationService.cs deleted file mode 100644 index 138c3e9601..0000000000 --- a/SampleApplications/Samples/GDS/AuthorizationService.cs +++ /dev/null @@ -1,449 +0,0 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Owin.Hosting; -using Owin; -using IdentityServer3.Core.Configuration; -using IdentityServer3.Core.Models; -using IdentityServer3.Core.Services; -using IdentityServer3.Core.Validation; -using IdentityServer3.Core.Services.Default; -using System.Security.Cryptography.X509Certificates; -using Opc.Ua.Configuration; -using Serilog; -using System.Security.Claims; -using Microsoft.Owin; -using System.IO; -using IdentityServer3.Core.Services.InMemory; -using System.IdentityModel.Tokens.Jwt; - -namespace Opc.Ua.AuthorizationService -{ - public class AuthorizationService - { - private IDisposable m_host; - private ApplicationInstance m_application; - - public async void Start(ApplicationInstance application) - { - Startup.ServiceCertificate = await application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.Find(); - - string hostname = System.Net.Dns.GetHostName(); - - foreach (var baseAddress in application.ApplicationConfiguration.ServerConfiguration.BaseAddresses) - { - Uri url = new Uri(baseAddress); - - if (url.Scheme == "https" && url.DnsSafeHost != "localhost") - { - hostname = url.DnsSafeHost; - break; - } - } - - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .WriteTo.LiterateConsole() - .CreateLogger(); - - m_host = WebApp.Start(String.Format("https://{0}:54333", hostname)); - m_application = application; - } - } - - public class Startup - { - public static X509Certificate2 ServiceCertificate; - - public void Configuration(IAppBuilder app) - { - var factory = new IdentityServerServiceFactory().UseInMemoryScopes(Scopes.Get()).UseInMemoryUsers(Users.Get()); - - factory.TokenService = new Registration(typeof(CustomTokenService)); - factory.CorsPolicyService = new Registration(new DefaultCorsPolicyService { AllowAll = true }); - factory.SecretParsers = new Registration[] { new Registration(new ApplicationCertificateSecretParser()) }; - factory.SecretValidators = new Registration[] { new Registration(new ApplicationCertificateSecretValidator()) }; - factory.ClientStore = new Registration(new ApplicationClientStore()); - factory.CustomGrantValidators.Add(new Registration(typeof(CustomGrantValidator))); - - var options = new IdentityServerOptions - { - SiteName = "GDS AuthorizationService", - - SigningCertificate = LoadCertificate(), - Factory = factory, - InputLengthRestrictions = new InputLengthRestrictions() { Password = 2048 }, - - EventsOptions = new EventsOptions - { - RaiseSuccessEvents = true, - RaiseErrorEvents = true, - RaiseFailureEvents = true, - RaiseInformationEvents = true - }, - }; - - app.UseIdentityServer(options); - } - - X509Certificate2 LoadCertificate() - { - return Startup.ServiceCertificate; - } - } - - static class Users - { - public static List Get() - { - return new List(); - } - } - - static class Scopes - { - public static List Get() - { - return new List - { - new Scope { Name = "gdsadmin" }, - new Scope { Name = "appadmin" }, - new Scope { Name = "pubsub" }, - new Scope { Name = "pubsub:secret" }, - new Scope { Name = "observer" } - }; - } - } - - public class ApplicationClientStore : IClientStore - { - /// - /// Initializes a new instance of the class. - /// - /// The inner . - /// The cache. - /// - /// inner - /// or - /// cache - /// - public ApplicationClientStore() - { - } - - /// - /// Finds a client by id - /// - /// The client id - /// - /// The client - /// - public Task FindClientByIdAsync(string clientId) - { - if (clientId == "urn:localhost:OAuth2TestClient") - { - return Task.FromResult(new IdentityServer3.Core.Models.Client - { - ClientName = "OAuth2TestClient", - ClientId = clientId, - Enabled = true, - AccessTokenType = AccessTokenType.Jwt, - Flow = Flows.ClientCredentials, - ClientSecrets = new List { new Secret("secret".Sha256()) }, - AllowClientCredentialsOnly = true, - AllowAccessToAllScopes = true - }); - } - - // TBD - look up ApplicationUri in DB. - - return Task.FromResult(new IdentityServer3.Core.Models.Client - { - ClientName = "Global Discovery Client", - ClientId = clientId, - Enabled = true, - AccessTokenType = AccessTokenType.Jwt, - Flow = Flows.Custom, - ClientSecrets = new List(), - AllowAccessToAllCustomGrantTypes = true, - AllowedCustomGrantTypes = new List { "urn:opcfoundation.org:oauth2:site_token" }, - AllowAccessToAllScopes = true - }); - } - } - - /// - /// Parses the environment for an X509 client certificate - /// - public class ApplicationCertificateSecretParser : ISecretParser - { - /// - /// Tries to find a secret on the environment that can be used for authentication - /// - /// The environment. - /// - /// A parsed secret - /// - public async Task ParseAsync(IDictionary environment) - { - var context = new OwinContext(environment); - - if (!context.Request.Body.CanSeek) - { - var copy = new MemoryStream(); - await context.Request.Body.CopyToAsync(copy); - copy.Seek(0L, SeekOrigin.Begin); - context.Request.Body = copy; - } - - context.Request.Body.Seek(0L, SeekOrigin.Begin); - var body = await context.Request.ReadFormAsync(); - context.Request.Body.Seek(0L, SeekOrigin.Begin); - - var grantType = body.Get("grant_type"); - - if (String.IsNullOrEmpty(grantType)) - { - return null; - } - - var clientId = body.Get("client_id"); - - if (String.IsNullOrEmpty(clientId)) - { - return null; - } - - var clientSecret = body.Get("client_secret"); - - if (String.IsNullOrEmpty(clientSecret)) - { - return null; - } - - if (grantType == "client_credentials") - { - return new ParsedSecret - { - Id = clientId, - Credential = clientSecret.Sha256(), - Type = "SharedSecret" - }; - } - - var certificate = Convert.FromBase64String(clientId); - - var signature = Convert.FromBase64String(clientSecret); - - var data = body.Get("access_token"); - - if (String.IsNullOrEmpty(data)) - { - return null; - } - - var accessToken = data; - - data = body.Get("nonce"); - - if (String.IsNullOrEmpty(data)) - { - return null; - } - - var nonce = Convert.FromBase64String(data); - - try - { - X509Certificate2 x509 = new X509Certificate2(certificate); - // TBD - use a CertificateValidator to verify certificate. - - // check that the id matches the certificate. - var applicationUri = Utils.GetApplicationUriFromCertificate(x509); - - // verify signature. - var dataToVerify = Utils.Append(new UTF8Encoding(false).GetBytes(accessToken), nonce); - - if (!RsaUtils.RsaPkcs15Sha1_Verify(new ArraySegment(dataToVerify), signature, x509)) - { - return null; - } - - return new ParsedSecret - { - Id = applicationUri, - Credential = x509, - Type = "ApplicationSignature" - }; - } - catch (Exception) - { - return null; - } - } - } - - /// - /// Validates a secret based on the thumbprint of an X509 Certificate - /// - public class ApplicationCertificateSecretValidator : ISecretValidator - { - /// - /// Validates a secret - /// - /// The stored secrets. - /// The received secret. - /// - /// A validation result - /// - /// ParsedSecret.Credential is not an X509 Certificate - public Task ValidateAsync(IEnumerable secrets, ParsedSecret parsedSecret) - { - var fail = Task.FromResult(new SecretValidationResult { Success = false }); - var success = Task.FromResult(new SecretValidationResult { Success = true }); - - if (parsedSecret.Type == "SharedSecret") - { - foreach (var secret in secrets) - { - if (secret.Value.Equals(parsedSecret.Credential)) - { - return success; - } - } - - return fail; - } - - if (parsedSecret.Type != "ApplicationSignature") - { - return fail; - } - - var certificate = parsedSecret.Credential as X509Certificate2; - - if (certificate == null) - { - throw new ArgumentException("ParsedSecret.Credential is not an X509 Certificate"); - } - - return success; - } - } - - class CustomGrantValidator : ICustomGrantValidator - { - public Task ValidateAsync(ValidatedTokenRequest request) - { - var accessToken = request.Raw.Get("access_token"); - var identity = JwtUtils.ValidateToken(new Uri("https://login.microsoftonline.com/opcfoundationprototyping.onmicrosoft.com"), "https://localhost:62540/prototypeserver", accessToken); - IssuedIdentityToken token = identity.GetIdentityToken() as IssuedIdentityToken; - JwtSecurityToken azureToken = new JwtSecurityToken(new UTF8Encoding(false).GetChars(token.DecryptedTokenData).ToString()); - - var scope = request.Raw.Get("scope"); - var nonce = request.Raw.Get("nonce"); - - DateTime now = DateTime.UtcNow; - double maxClockSkewInMinutes = 10; - - if (azureToken.ValidFrom.AddMinutes(-maxClockSkewInMinutes) > now || azureToken.ValidTo.AddMinutes(maxClockSkewInMinutes) < now) - { - return Task.FromResult(new CustomGrantValidationResult( - "Access token provided with the request has expired (" + - azureToken.ValidTo.ToLocalTime().ToString("yyy-MM-dd HH:mm:ss") + - ") or is not yet valid (" + - azureToken.ValidFrom.ToLocalTime().ToString("yyy-MM-dd HH:mm:ss") + ").")); - } - - List claims = new List(); - string subject = request.Client.ClientId; - - foreach (var claim in azureToken.Claims) - { - switch (claim.Type) - { - case "unique_name": { subject = claim.Value; claims.Add(claim); break; } - case "name": { claims.Add(claim); break; } - } - } - - claims.Add(new Claim("nonce", nonce)); - - request.Client.AccessTokenLifetime = (int)(azureToken.ValidTo - now).TotalSeconds; - - var result = new CustomGrantValidationResult( - subject, - "site_token", - claims, - "gds"); - - return Task.FromResult(result); - } - - public string GrantType - { - get { return "urn:opcfoundation.org:oauth2:site_token"; } - } - } - - class CustomTokenService : DefaultTokenService - { - public CustomTokenService(IdentityServerOptions options, IClaimsProvider claimsProvider, ITokenHandleStore tokenHandles, ITokenSigningService signingService, IEventService events) - : base(options, claimsProvider, tokenHandles, signingService, events) - { - } - - public async override Task CreateAccessTokenAsync(TokenCreationRequest request) - { - var token = await base.CreateAccessTokenAsync(request); - - token.Lifetime = token.Client.AccessTokenLifetime; - - /* - var claims = new List(); - claims.AddRange(await _claimsProvider.GetAccessTokenClaimsAsync( - request.Subject, - request.Client, - request.Scopes, - request.ValidatedRequest)); - - if (request.Client.IncludeJwtId) - { - claims.Add(new Claim(Constants.ClaimTypes.JwtId, CryptoRandom.CreateUniqueId())); - } - - if (request.ProofKey.IsPresent()) - { - claims.Add(new Claim(Constants.ClaimTypes.Confirmation, request.ProofKey, Constants.ClaimValueTypes.Json)); - } - - var token = new Token(Constants.TokenTypes.AccessToken) - { - Audience = string.Format(Constants.AccessTokenAudience, IssuerUri.EnsureTrailingSlash()), - Issuer = IssuerUri, - Lifetime = request.Client.AccessTokenLifetime, - Claims = claims.Distinct(new ClaimComparer()).ToList(), - Client = request.Client - }; - */ - - var resource = request.ValidatedRequest.Raw["resource"]; - - if (String.IsNullOrEmpty(resource)) - { - token.Audience = Namespaces.OAuth2SiteResourceUri; - } - else - { - token.Audience = resource; - } - - UriBuilder uri = new UriBuilder(token.Issuer); - uri.Host = uri.Host.ToLowerInvariant(); - token.Issuer = uri.ToString(); - - return token; - } - } -} diff --git a/SampleApplications/Samples/GDS/GlobalDiscoveryServer.csproj b/SampleApplications/Samples/GDS/GlobalDiscoveryServer.csproj index 01ebb4f41a..5c46175126 100644 --- a/SampleApplications/Samples/GDS/GlobalDiscoveryServer.csproj +++ b/SampleApplications/Samples/GDS/GlobalDiscoveryServer.csproj @@ -68,34 +68,6 @@ ..\..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll True - - ..\..\..\packages\IdentityServer3.2.5.1\lib\net45\IdentityServer3.dll - True - - - ..\..\..\packages\Microsoft.IdentityModel.Logging.1.0.0\lib\net451\Microsoft.IdentityModel.Logging.dll - True - - - ..\..\..\packages\Microsoft.IdentityModel.Tokens.5.0.0\lib\net451\Microsoft.IdentityModel.Tokens.dll - True - - - ..\..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll - True - - - ..\..\..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll - True - - - ..\..\..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll - True - - - ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - True - False ..\..\SDK\Opc.Ua.Configuration\bin\Debug\net46\Opc.Ua.Configuration.dll @@ -108,18 +80,6 @@ False ..\..\SDK\Opc.Ua.Server\bin\Debug\net46\Opc.Ua.Server.dll - - ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll - True - - - ..\..\..\packages\Serilog.2.1.0\lib\net45\Serilog.dll - True - - - ..\..\..\packages\Serilog.Sinks.Literate.2.0.0\lib\net45\Serilog.Sinks.Literate.dll - True - @@ -133,38 +93,24 @@ 3.0 - - ..\..\..\packages\System.IdentityModel.Tokens.Jwt.5.0.0\lib\net451\System.IdentityModel.Tokens.Jwt.dll - True - - - ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll - True - 3.0 3.0 - - ..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll - True - - - ResXFileCodeGenerator Resources.Designer.cs diff --git a/SampleApplications/Samples/GDS/GlobalDiscoveryServerServer.cs b/SampleApplications/Samples/GDS/GlobalDiscoveryServerServer.cs index 00c01ab8a0d6d3b140dc601365352107614064f6..c1328dd01758c85fc49ef0793fdb3e0ec2422726 100644 GIT binary patch delta 43 zcmV+`0M!51hXbB~1F$L%vw99*Uk6kGPXI&!Pm{4E9h1l delta 407 zcmZWkPfG%E5Pe~Zl!$^*gym+WskI=N|WLk96kdfk$>T_)EERVVdC2jh_u}ZFm6m_#Oh)#2-&A+^w^QqY4-VFN&j!;HXzPD%P zdCw`{xId~ task2 = application.CheckApplicationInstanceCertificate(false, 0); task2.Wait(); - // add handler. - application.ApplicationConfiguration.CertificateValidator.CertificateValidation += CertificateValidator_CertificateValidation; - - // start authorization service. - var aus = new Opc.Ua.AuthorizationService.AuthorizationService(); - aus.Start(application); - // start the server. var server = new GlobalDiscoveryServerServer(); Task task3 = application.Start(server); @@ -83,14 +76,5 @@ namespace Opc.Ua.GdsServer return; } } - - static void CertificateValidator_CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e) - { - // automatically accept all untrusted certficates. - if (e.Error.Code == StatusCodes.BadCertificateUntrusted) - { - e.Accept = true; - } - } } } diff --git a/SampleApplications/Samples/GDS/SelfHost.cs b/SampleApplications/Samples/GDS/SelfHost.cs deleted file mode 100644 index 092142fa36..0000000000 --- a/SampleApplications/Samples/GDS/SelfHost.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Web.Http; - -namespace Opc.Ua.GdsServer -{ - public class ProductsController : ApiController - { - Product[] products = new Product[] - { - new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, - new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, - new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } - }; - - public IEnumerable GetAllProducts() - { - return products; - } - - public Product GetProductById(int id) - { - var product = products.FirstOrDefault((p) => p.Id == id); - if (product == null) - { - throw new HttpResponseException(HttpStatusCode.NotFound); - } - return product; - } - - public IEnumerable GetProductsByCategory(string category) - { - return products.Where(p => string.Equals(p.Category, category, - StringComparison.OrdinalIgnoreCase)); - } - } - - public class Product - { - public int Id { get; set; } - public string Name { get; set; } - public string Category { get; set; } - public decimal Price { get; set; } - } -} diff --git a/SampleApplications/Samples/GDS/packages.config b/SampleApplications/Samples/GDS/packages.config index 049bfbdf44..c089e85e2e 100644 --- a/SampleApplications/Samples/GDS/packages.config +++ b/SampleApplications/Samples/GDS/packages.config @@ -1,17 +1,4 @@  - - - - - - - - - - - - - \ No newline at end of file