diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2019-02-24 00:57:14 +0200 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2019-02-24 00:57:14 +0200 |
| commit | 0adea9eb464a3f2d5d73b2c8c26d32e0d1a3874b (patch) | |
| tree | bb5e4055020aa4417e1f7703a611353ce44689d6 /Software/Visual_Studio/Tango.Web/Security | |
| parent | 17612c08da93c75d4c941a643bc7602c18f351d8 (diff) | |
| download | Tango-0adea9eb464a3f2d5d73b2c8c26d32e0d1a3874b.tar.gz Tango-0adea9eb464a3f2d5d73b2c8c26d32e0d1a3874b.zip | |
Working on refresh tokens...
Diffstat (limited to 'Software/Visual_Studio/Tango.Web/Security')
6 files changed, 327 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.Web/Security/RefreshTokenEntity.cs b/Software/Visual_Studio/Tango.Web/Security/RefreshTokenEntity.cs new file mode 100644 index 000000000..839027ca1 --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/RefreshTokenEntity.cs @@ -0,0 +1,24 @@ +using Microsoft.WindowsAzure.Storage.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Web.Security +{ + public class RefreshTokenEntity : TableEntity + { + /// <summary> + /// Initializes a new instance of the <see cref="RefreshTokenEntity"/> class. + /// </summary> + public RefreshTokenEntity() + { + + } + + public String RefreshToken { get; set; } + public String AccessToken { get; set; } + public DateTime Expiration { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.Web/Security/RenewTokenRequest.cs b/Software/Visual_Studio/Tango.Web/Security/RenewTokenRequest.cs new file mode 100644 index 000000000..213cd3afd --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/RenewTokenRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport.Web; + +namespace Tango.Web.Security +{ + public class RenewTokenRequest : WebRequestMessage + { + public String RefreshToken { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.Web/Security/RenewTokenResponse.cs b/Software/Visual_Studio/Tango.Web/Security/RenewTokenResponse.cs new file mode 100644 index 000000000..76c381852 --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/RenewTokenResponse.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport.Web; + +namespace Tango.Web.Security +{ + public class RenewTokenResponse : WebTokenResponse + { + + } +} diff --git a/Software/Visual_Studio/Tango.Web/Security/TokensManager.cs b/Software/Visual_Studio/Tango.Web/Security/TokensManager.cs new file mode 100644 index 000000000..bf5574766 --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/TokensManager.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Authentication; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport.Web; + +namespace Tango.Web.Security +{ + public class TokensManager<T> where T : IEquatable<T> + { + private Dictionary<String, TokenWrapper> _tokens; + + private class TokenWrapper : IEquatable<TokenWrapper> + { + public WebToken WebToken { get; set; } + + public T Value { get; set; } + + public bool Equals(TokenWrapper other) + { + return Value.Equals(other.Value); + } + } + + public TokensManager() + { + _tokens = new Dictionary<string, TokenWrapper>(); + ExpirationTime = TimeSpan.FromHours(1); + } + + public TimeSpan ExpirationTime { get; set; } + + public WebToken GetOrCreate(T tokenObject) + { + var existing_token = _tokens.FirstOrDefault(x => x.Value.Value.Equals(tokenObject)); + + if (existing_token.Key != null) + { + return existing_token.Value.WebToken; + } + else + { + String token = Guid.NewGuid().ToString(); + TokenWrapper wrapper = new TokenWrapper() + { + Value = tokenObject, + WebToken = new WebToken() + { + //AccessToken = token, + //Expiration = DateTime.UtcNow.Add(ExpirationTime) + }, + }; + + _tokens.Add(token, wrapper); + return wrapper.WebToken; + } + } + + public void Validate(String token) + { + GetTokenObject(token); + } + + public T GetTokenObject(String token) + { + if (!_tokens.ContainsKey(token)) + { + throw new AuthenticationException("Invalid token."); + } + + if (DateTime.UtcNow > _tokens[token].WebToken.Expiration) + { + _tokens.Remove(token); + throw new TokenExpiredException("Session Expired."); + } + + return _tokens[token].Value; + } + } +} diff --git a/Software/Visual_Studio/Tango.Web/Security/WebToken.cs b/Software/Visual_Studio/Tango.Web/Security/WebToken.cs new file mode 100644 index 000000000..006ed9de7 --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/WebToken.cs @@ -0,0 +1,178 @@ +using JWT; +using JWT.Algorithms; +using JWT.Builder; +using JWT.Serializers; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Web.Security +{ + public class WebToken + { + public DateTime Issued { get; protected set; } + public DateTime? Expiration { get; protected set; } + public String AccessToken { get; protected set; } + public String RefreshToken { get; protected set; } + + public WebToken() + { + + } + + public static WebToken CreateNew(String secret, DateTime? expiration = null) + { + DateTime issued = DateTime.UtcNow; + + var builder = new JwtBuilder() + .WithAlgorithm(new HMACSHA256Algorithm()) + .WithSecret(secret) + .IssuedAt(issued); + + if (expiration != null) + { + builder = builder.ExpirationTime(expiration.Value); + } + + builder = builder.AddClaim("object", null); + + return new WebToken() + { + AccessToken = builder.Build(), + RefreshToken = Guid.NewGuid().ToString(), + Expiration = expiration, + Issued = issued, + }; + } + + public static void Validate(String secret, String token) + { + var json = new JwtBuilder() + .WithSecret(secret) + .MustVerifySignature() + .Decode(token); + } + + public void Validate(String secret) + { + var json = new JwtBuilder() + .WithSecret(secret) + .MustVerifySignature() + .Decode(AccessToken); + } + + public WebToken Renew(String secret, String token) + { + WebToken webToken = WebToken.FromToken(token); + var newToken = CreateNew(secret, DateTime.UtcNow.Add(webToken.Expiration.Value - webToken.Issued)); + newToken.RefreshToken = webToken.RefreshToken; + return newToken; + } + + public static WebToken FromToken(String token) + { + WebToken webToken = new WebToken(); + + var payload = new JwtBuilder() + .WithValidator(null) + .Decode<IDictionary<string, object>>(token); + + webToken.AccessToken = token; + + if (payload.ContainsKey("exp")) + { + long exp = long.Parse(payload["exp"].ToString()); + webToken.Expiration = ConvertEpochToDateTime(exp); + } + + if (payload.ContainsKey("iat")) + { + long iat = long.Parse(payload["iat"].ToString()); + webToken.Issued = ConvertEpochToDateTime(iat); + } + + return webToken; + } + + protected static DateTime ConvertEpochToDateTime(long seconds) + { + var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + return epoch.AddSeconds(seconds); + } + } + + public class WebToken<T> : WebToken where T : class + { + public T Object { get; protected set; } + + private WebToken() + { + + } + + public static WebToken<T> CreateNew(String secret, T obj = null, DateTime? expiration = null) + { + DateTime issued = DateTime.UtcNow; + + var builder = new JwtBuilder() + .WithAlgorithm(new HMACSHA256Algorithm()) + .WithSecret(secret) + .IssuedAt(issued); + + if (expiration != null) + { + builder = builder.ExpirationTime(expiration.Value); + } + + builder = builder.AddClaim("object", obj); + + return new WebToken<T>() + { + AccessToken = builder.Build(), + RefreshToken = Guid.NewGuid().ToString(), + Expiration = expiration, + Issued = issued, + Object = obj, + }; + } + + public static new WebToken<T> FromToken(String token) + { + WebToken<T> webToken = new WebToken<T>(); + + var payload = new JwtBuilder() + .WithValidator(null) + .Decode<IDictionary<string, object>>(token); + + webToken.AccessToken = token; + + if (payload.ContainsKey("exp")) + { + long exp = long.Parse(payload["exp"].ToString()); + webToken.Expiration = ConvertEpochToDateTime(exp); + } + + if (payload.ContainsKey("iat")) + { + long iat = long.Parse(payload["iat"].ToString()); + webToken.Issued = ConvertEpochToDateTime(iat); + } + + webToken.Object = JsonConvert.DeserializeObject<T>(payload["object"].ToString()); + + return webToken; + } + + public new WebToken<T> Renew(String secret, String token) + { + WebToken<T> webToken = WebToken<T>.FromToken(token); + var newToken = WebToken<T>.CreateNew(secret, webToken.Object, DateTime.UtcNow.Add(webToken.Expiration.Value - webToken.Issued)); + newToken.RefreshToken = webToken.RefreshToken; + return newToken; + } + } +} diff --git a/Software/Visual_Studio/Tango.Web/Security/WebTokenResponse.cs b/Software/Visual_Studio/Tango.Web/Security/WebTokenResponse.cs new file mode 100644 index 000000000..8c8f2f096 --- /dev/null +++ b/Software/Visual_Studio/Tango.Web/Security/WebTokenResponse.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Transport.Web; + +namespace Tango.Web.Security +{ + public class WebTokenResponse : WebResponseMessage + { + public String AccessToken { get; set; } + public String RefreshToken { get; set; } + } +} |
