/// <summary> /// TODO unit test this. /// </summary> /// <param name="jwt"></param> /// <param name="secretKey"></param> /// <returns></returns> public bool IsValidJwt(string jwt, string secretKey) { if (string.IsNullOrWhiteSpace(jwt)) { return(false); } try { string jsonPayload = ""; jsonPayload = JWT.JsonWebToken.Decode(jwt, secretKey, false); // JWT.SignatureVerificationException JwtClaims claims = JsonConvert.DeserializeObject <JwtClaims>(jsonPayload); TimeSpan ts = claims.expires - DateTime.UtcNow; if (ts.TotalSeconds <= 0) { return(false); } if (claims.iss != _app.GetSetting("SiteDomain")?.Value) { return(false); } } catch (Exception ex) { Debug.Assert(false, ex.Message); return(false); } return(true); }
public void TestReqeustParamsDeserialization() { var json = @"{""aud"":""svc:f8329e0e-dd7a-11e7-98b4-469158467b1a"",""iss"":""lka"",""cty"":""application/json"",""nbf"":1513716853,""jti"":""c70da9cf498049ff9fd465c87d233d36"",""exp"":1513716858,""iat"":1513716853,""request"":{""path"":""path"",""meth"":""POST"",""hash"":""7214a12199440f792227fc9310193a2267f364ee59bfe0495ea690c31033325b"",""func"":""S256""},""sub"":""svc:f8329e0e-dd7a-11e7-98b4-469158467b1a""}"; var claims = JwtClaims.FromJson(json); Assert.AreEqual(claims.Audience, "svc:f8329e0e-dd7a-11e7-98b4-469158467b1a"); Assert.AreEqual(claims.Issuer, "lka"); Assert.AreEqual(claims.Subject, "svc:f8329e0e-dd7a-11e7-98b4-469158467b1a"); Assert.IsNotNull(claims.NotBefore); Assert.IsNotNull(claims.IssuedAt); Assert.IsNotNull(claims.ExpiresAt); Assert.AreEqual(claims.NotBefore, DateTime.Parse("12/19/2017 8:54:13 PM")); Assert.AreEqual(claims.IssuedAt, DateTime.Parse("12/19/2017 8:54:13 PM")); Assert.AreEqual(claims.ExpiresAt, DateTime.Parse("12/19/2017 8:54:18 PM")); Assert.AreEqual(claims.TokenId, "c70da9cf498049ff9fd465c87d233d36"); Assert.IsNotNull(claims.Request); Assert.AreEqual(claims.Request.Method, "POST"); Assert.AreEqual(claims.Request.Path, "path"); Assert.AreEqual(claims.Request.ContentHash, "7214a12199440f792227fc9310193a2267f364ee59bfe0495ea690c31033325b"); Assert.AreEqual(claims.Request.ContentHashAlgorithm, "S256"); }
public void TestSampleDeserializtion() { var json = "{\"aud\":\"svc:f8329e0e-dd7a-11e7-98b4-469158467b1a\",\"iss\":\"lka\",\"cty\":\"application/json\",\"nbf\":1513716853,\"jti\":\"c70da9cf498049ff9fd465c87d233d36\",\"exp\":1513716858,\"iat\":1513716853,\"response\":{\"status\":400,\"hash\":\"7214a12199440f792227fc9310193a2267f364ee59bfe0495ea690c31033325b\",\"func\":\"S256\"},\"sub\":\"svc:f8329e0e-dd7a-11e7-98b4-469158467b1a\"}"; var claims = JwtClaims.FromJson(json); Assert.AreEqual(claims.Audience, "svc:f8329e0e-dd7a-11e7-98b4-469158467b1a"); Assert.AreEqual(claims.Issuer, "lka"); Assert.AreEqual(claims.Subject, "svc:f8329e0e-dd7a-11e7-98b4-469158467b1a"); Assert.IsNotNull(claims.NotBefore); Assert.IsNotNull(claims.IssuedAt); Assert.IsNotNull(claims.ExpiresAt); Assert.AreEqual(claims.NotBefore, DateTime.Parse("12/19/2017 8:54:13 PM")); Assert.AreEqual(claims.IssuedAt, DateTime.Parse("12/19/2017 8:54:13 PM")); Assert.AreEqual(claims.ExpiresAt, DateTime.Parse("12/19/2017 8:54:18 PM")); Assert.AreEqual(claims.TokenId, "c70da9cf498049ff9fd465c87d233d36"); Assert.IsNotNull(claims.Response); Assert.AreEqual(claims.Response.StatusCode, 400); Assert.AreEqual(claims.Response.ContentHash, "7214a12199440f792227fc9310193a2267f364ee59bfe0495ea690c31033325b"); Assert.AreEqual(claims.Response.ContentHashAlgorithm, "S256"); }
/// <summary> /// Get claims of user. /// </summary> /// <returns>User claims.</returns> protected JwtClaims GetUserClaims() { var claims = this.User.Claims; var jwtClaims = new JwtClaims { FromId = claims.Where(claim => claim.Type == "userObjectIdentifier").Select(claim => claim.Value).First(), ServiceUrl = claims.Where(claim => claim.Type == "serviceURL").Select(claim => claim.Value).First(), }; return(jwtClaims); }
/// <summary> /// Get claims of user. /// </summary> /// <returns>User claims.</returns> private JwtClaims GetUserClaims() { var claims = this.httpContextAccessor.HttpContext.User.Claims; var jwtClaims = new JwtClaims { FromId = claims?.Where(claim => claim.Type == "fromId").Select(claim => claim.Value).FirstOrDefault(), ServiceUrl = claims?.Where(claim => claim.Type == "serviceURL").Select(claim => claim.Value).FirstOrDefault(), }; return(jwtClaims); }
/// <summary> /// Get claims of user. /// </summary> /// <returns>User claims.</returns> protected JwtClaims GetUserClaims() { var claims = this.User.Claims; var jwtClaims = new JwtClaims { FromId = claims.Where(claim => claim.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").Select(claim => claim.Value).First(), Upn = claims.Where(claim => claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn").Select(claim => claim.Value).First(), }; return(jwtClaims); }
/// <summary> /// Get claims of user. /// </summary> /// <returns>User claims.</returns> protected JwtClaims GetUserClaims() { var claims = this.User.Claims; var jwtClaims = new JwtClaims { FromId = claims.Where(claim => claim.Type == "fromId").Select(claim => claim.Value).First(), ServiceUrl = claims.Where(claim => claim.Type == "applicationBasePath").Select(claim => claim.Value).First(), }; return(jwtClaims); }
public User GetUserFromToken(string authToken) { JwtClaims jwtClaims = ParseJwtToken(authToken); return(new User() { Id = jwtClaims.Id, Email = jwtClaims.Email, Role = jwtClaims.Role }); }
public AuthenticationStatus Authenticate(string authToken, out User user) { var result = AuthenticationStatus.Success; user = null; if (string.IsNullOrWhiteSpace(authToken)) { throw new AuthenticationException("Token is not provided"); } try { IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); JwtClaims jwtClaims = decoder.DecodeToObject <JwtClaims>(authToken); user = new User() { Id = jwtClaims.Id, Role = jwtClaims.Role, Email = jwtClaims.Email }; if (_jwtSettings.IsEnabled) { decoder.Decode(authToken, _jwtSettings.SignatureSecret, verify: true); } else { result = AuthenticationStatus.ClientDisabled; } } catch (TokenExpiredException) { result = AuthenticationStatus.TokenExpired; } catch (SignatureVerificationException) { result = AuthenticationStatus.TokenVerificationFailed; } return(result); }
public string GetProfileUUID(string authToken) { if (string.IsNullOrWhiteSpace(authToken)) { return(authToken); } _appManager = new AppManager(Globals.DBConnectionKey, "web", authToken); string appSecret = _appManager.GetSetting("AppKey")?.Value; JwtClaims requestorClaims = null; try { var payload = JWT.JsonWebToken.Decode(authToken, appSecret, false); requestorClaims = JsonConvert.DeserializeObject <JwtClaims>(payload); TimeSpan ts = requestorClaims.Expires - DateTime.UtcNow; if (ts.TotalSeconds <= 0) { return(string.Empty); } string[] tokens = requestorClaims.aud.Replace(SystemFlag.Default.Account, "systemdefaultaccount").Split('.'); if (tokens.Length == 0) { return(string.Empty); } //string userUUID = tokens[0]; //string accountUUID = tokens[1]; //if ("systemdefaultaccount" == accountUUID) accountUUID = SystemFlag.Default.Account; string profileUUID = tokens[2]; return(profileUUID); } catch (Exception ex) { return(string.Empty); } }
private void ValidatePrivateClaims(HttpResponse response, JwtClaims jwt) { // verify response information matches the JWT if (response.Headers[HttpResponseHeader.Location] != jwt.Response.LocationHeader) { throw new JwtError("Location header of response content does not match JWT response location"); } string[] expectedCacheControlHeaders = new string[] { }; if (jwt.Response.CacheControlHeader != null) { expectedCacheControlHeaders = jwt.Response.CacheControlHeader.Split(',').Select(x => x.Trim()).ToArray(); Array.Sort(expectedCacheControlHeaders); } var actualCacheControlHeaders = response.Headers.GetValues("cache-control") ?? new string[] { }; if (actualCacheControlHeaders != null) { Array.Sort(actualCacheControlHeaders); } if (!expectedCacheControlHeaders.SequenceEqual(actualCacheControlHeaders)) { throw new JwtError("Cache-Control header of response content does not match JWT response cache"); } if ((int)response.StatusCode != jwt.Response.StatusCode) { throw new JwtError("Status code of response content does not match JWT response status code"); } // if the response has body content, we need to validate the hash if (!string.IsNullOrWhiteSpace(response.ResponseBody)) { ValidateHash(response.ResponseBody, jwt.Response.ContentHashAlgorithm, jwt.Response.ContentHash); } }
public string CreateJwt(string secretKey, User user, string issuer, DateTime expires) { if (user == null) { return(string.Empty); } string profileUUID = string.Empty; using (var context = new GreenWerxDbContext(this._connectionKey)) { var profile = context.GetAll <Profile>()?.FirstOrDefault(sw => sw?.AccountUUID == user.AccountUUID && sw?.UserUUID == user.UUID); profileUUID = profile?.UUID; } var payload = new JwtClaims(); if (string.IsNullOrWhiteSpace(profileUUID)) { payload.aud = user.UUID + "." + user.AccountUUID; } else { payload.aud = user.UUID + "." + user.AccountUUID + "." + profileUUID; } payload.iss = issuer; payload.jti = Guid.NewGuid().ToString(); payload.exp = expires.ConvertToUnixTimestamp().ToString(); payload.expires = expires; RoleManager roleManager = new RoleManager(this._connectionKey); List <Role> userRoles = roleManager.GetRolesForUser(user.UUID, user.AccountUUID); List <Role> profileRoles = roleManager.GetRolesForUser(profileUUID, user.AccountUUID); userRoles.AddRange(profileRoles); if (userRoles.Count > 0) { payload.roleWeights = userRoles.Select(s => s.RoleWeight.ToString()).Aggregate((current, next) => current + "," + next); payload.roleNames = userRoles.Select(s => s.Name?.ToUpper()).Aggregate((current, next) => current + "," + next); } //NOTE: This uses bouncy castle portable, specifically version 1.8.1. Runtime error occures with other versions. string token = JWT.JsonWebToken.Encode(payload, secretKey, JWT.JwtHashAlgorithm.HS256); return(token); #region Unsecured jwt example ////var hmac = new HMACSHA256(); ////var header = "{ \"alg\": \"HS256\", \"typ\": \"JWT\" }"; //////Some PayLoad that contain information about the customer ////var payload = "{ \"userUUID\": \"" + userUUID + "\", \"scope\": \"http://test.com\" }"; ////var secToken = hmac.ComputeHash(Encoding.UTF8.GetBytes(header + payload)); ////// Token to String so you can use it in your client ////Debug.Assert(false, "TODO NEED TO REMOVE THE END PADDING = OR == "); ////var tokenString = Convert.ToBase64String(Encoding.UTF8.GetBytes(header)) + "." + //// Convert.ToBase64String(Encoding.UTF8.GetBytes(payload)) + "." + //// Convert.ToBase64String(secToken); ////return tokenString; #endregion Unsecured jwt example }
private void LogRequest() { try { RequestLog req = new RequestLog(); req.Timer = new Stopwatch(); req.DateCreated = DateTime.UtcNow; req.RequestURL = HttpContext.Current.Request.Url.AbsoluteUri; req.AbsolutePath = HttpContext.Current.Request.Url.AbsolutePath; req.Referrer = HttpContext.Current.Request.UrlReferrer.AbsoluteUri; // ?.DnsSafeHost; req.RequestComplete = false; req.IPAddress = new NetworkHelper().GetClientIpAddress(HttpContext.Current.Request); req.Method = HttpContext.Current.Request.HttpMethod; req.RequestLocalPath = HttpContext.Current.Request.Path; req.RequestURL = HttpContext.Current.Request.Url.ToString(); var auth = HttpContext.Current.Request.Headers.GetValues("Authorization")?.ToString().Replace("Bearer ", ""); auth = auth?.Trim(); //IEnumerable<KeyValuePair<string, string>> kvp = actionContext.Request.GetQueryNameValuePairs(); //KeyValuePair<string, string> apiKVP = kvp.FirstOrDefault(w => w.Key.EqualsIgnoreCase("KEY")); //if (Globals.AddRequestPermissions) //{ // //if we need to pass the user object in, move this down below after it gets the current user. // RoleManager roleManager = new RoleManager(Globals.DBConnectionKey, null); // string name = roleManager.NameFromPath(absolutePath); // roleManager.CreatePermission(name, method, absolutePath, "api"); //} if (!string.IsNullOrWhiteSpace(auth)) { JwtClaims requestorClaims = null; try { _appManager = new AppManager(Globals.DBConnectionKey, "web", auth); string appSecret = _appManager.GetSetting("AppKey")?.Value; var payload = JWT.JsonWebToken.Decode(auth, appSecret, false); requestorClaims = JsonConvert.DeserializeObject <JwtClaims>(payload); string[] tokens = requestorClaims.aud.Replace(SystemFlag.Default.Account, "systemdefaultaccount").Split('.'); if (tokens.Length >= 2) { req.UserUUID = tokens[0]; req.AccountUUID = tokens[1]; } } catch { } } HttpContext.Current.Items.Add("RequestIdentity", req.UUID); // so we can find the request in the array in the function if (requests.Count < 200) { requests.Add(req); } else { for (int i = 0; i < requests.Count; i++) { if (requests[i].RequestComplete) { requests.Remove(requests[i]); continue; } TimeSpan elaps = DateTime.UtcNow - requests[i].DateCreated; if (elaps.TotalMinutes > 10) { requests.Remove(requests[i]); } } } req.Timer.Start(); } catch { } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers() .AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore ); services.AddAuthentication(o => { o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(); // use separate options below to allow dependency injection with rsa key to work. // Dependency injection for RSA key -> the instance of the rsa key needs to be a singleton services.AddOptions <JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme) .Configure <RsaSecurityKey>((options, skey) => { options.IncludeErrorDetails = true; // fix to map permissions as roles in .net mvc via event handling: options.Events = new JwtBearerEvents { OnTokenValidated = async ctx => { await Task.Run(() => { var newClaims = new List <Claim>(); foreach (Claim claim in ctx.Principal.Claims) { if (claim.Type == "user_claims") // we use this attribute chosen by the login service that contains the permissions to be converted to .net mvc identity roles. { JwtClaims claims = JsonSerializer.Deserialize <JwtClaims>(claim.Value); foreach (String permission in claims.permissions) { // add each permission as .net identity role for use in MVC controllers role filtering newClaims.Add(new Claim(ClaimTypes.Role, permission)); } } } // build new Claims Identity var appIdentity = new ClaimsIdentity(newClaims); // add the claims to the principal identity ctx.Principal.AddIdentity(appIdentity); }); } }; options.TokenValidationParameters.ValidateIssuer = false; options.TokenValidationParameters.ValidateAudience = false; options.TokenValidationParameters.ValidateIssuerSigningKey = true; options.TokenValidationParameters.IssuerSigningKey = skey; options.TokenValidationParameters.ValidateLifetime = false; options.TokenValidationParameters.RequireExpirationTime = true; options.TokenValidationParameters.RequireSignedTokens = true; }); // needed in order for the rsa validation key to remain in memory (for some reason it does not work otherwise). services.AddSingleton <RsaSecurityKey>(provider => { RSA rsa = RSA.Create(); rsa.ImportSubjectPublicKeyInfo( source: Convert.FromBase64String(@"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKZzT8MhSEHRRecmD1kM oW8unUYufupt/4AV5Yd6YSR84uHjMuArp/lQx/ROrCvt5xSBB547L5oPeJECeS4h p7Djlsd3VyIvs+yY+e9FM72MLnaoydQLCHKz8RQF2+mr8SeM/4va6vGSTTW3F5Ay 9LOYDsQa18yYJ+a7tc2PQJQGZYQvQ1YWerlScrcZQ1ChB5u+mALdg1VoKpW2n+bP 6ucjGidjqUbLMPKOHQRQBuoMNTXk2fzKQmhhML9lUKw5+2RZ2jtJKBVBNprV1EDP yBTXutHUCV6D4esOqc35e1jZo6kQGGaWQ0rIpupv/qyXLHTz6Gi/mnvZuMQJIJZ+ iwIDAQAB"), bytesRead: out int _); return(new RsaSecurityKey(rsa)); }); services.AddSingleton <ProductsFacade>(); services.AddSingleton <TagsFacade>(); services.AddSingleton <StocksFacade>(); services.AddSingleton <IRepositoryFactory, RepositoryFactory>(); services.AddSingleton <IEventBusPublisher, RabbitMessenger>(); services.AddApiVersioning(x => { x.DefaultApiVersion = new ApiVersion(0, 1); x.AssumeDefaultVersionWhenUnspecified = true; x.ReportApiVersions = true; }); services.AddVersionedApiExplorer(options => { options.GroupNameFormat = "VVVV"; options.SubstituteApiVersionInUrl = true; options.SubstitutionFormat = "VVVV"; }); services.AddSwaggerDocument(config => { config.DocumentName = "0.* (not for production)"; //config.ApiGroupNames = new[] { "0.1" }; config.SchemaNameGenerator = new SchemaNameGenerator(); // Authentication config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token")); config.AddSecurity("JWT token", Enumerable.Empty <string>(), new OpenApiSecurityScheme() { Type = OpenApiSecuritySchemeType.ApiKey, Name = "Authorization", In = OpenApiSecurityApiKeyLocation.Header, Description = "Copy this into the value field: \nBearer {my long token}" } ); config.PostProcess = document => { document.Info.Version = "0.1"; document.Info.Title = "Inventory Microservice API"; document.Info.Description = "API Documentation"; }; }); }