mirror of
https://github.com/cadmium-im/zirconium-sharp.git
synced 2024-11-08 11:41:04 +00:00
Refactor auth system: make token creation/validation fully pluggable
This commit is contained in:
parent
eb849a8388
commit
dea57a3cb2
@ -1,9 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using JWT.Algorithms;
|
||||
using JWT.Builder;
|
||||
using Newtonsoft.Json;
|
||||
using Zirconium.Utils;
|
||||
using Zirconium.Core.Plugins.Interfaces;
|
||||
using System.Linq;
|
||||
|
||||
@ -27,15 +23,8 @@ namespace Zirconium.Core
|
||||
|
||||
public string CreateToken(string entityID, string deviceID, long tokenExpirationMillis)
|
||||
{
|
||||
JWTPayload payload = new JWTPayload();
|
||||
payload.DeviceID = deviceID;
|
||||
payload.EntityID = entityID;
|
||||
return new JwtBuilder()
|
||||
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
||||
.WithSecret(_secretString)
|
||||
.AddClaim("exp", DateTimeOffset.UtcNow.AddMilliseconds(tokenExpirationMillis).ToUnixTimeSeconds())
|
||||
.AddClaims(payload.ToDictionary())
|
||||
.Encode();
|
||||
if (DefaultAuthProvider == null) throw new Exception("Default auth provider isn't specified");
|
||||
return DefaultAuthProvider.CreateAuthToken(entityID, deviceID, tokenExpirationMillis);
|
||||
}
|
||||
|
||||
public string CreateToken(string entityID, string deviceID)
|
||||
@ -43,22 +32,10 @@ namespace Zirconium.Core
|
||||
return CreateToken(entityID, deviceID, DEFAULT_TOKEN_EXPIRATION_TIME_HOURS);
|
||||
}
|
||||
|
||||
public JWTPayload ValidateToken(string token)
|
||||
public SessionAuthData ValidateToken(string token)
|
||||
{
|
||||
var jsonPayload = new JwtBuilder()
|
||||
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
||||
.WithSecret(_secretString)
|
||||
.MustVerifySignature()
|
||||
.Decode(token);
|
||||
var payload = JsonConvert.DeserializeObject<JWTPayload>(jsonPayload);
|
||||
if (DefaultAuthProvider == null)
|
||||
{
|
||||
throw new Exception("Default auth provider isn't specified");
|
||||
}
|
||||
var validToken = DefaultAuthProvider.TestToken(token, payload);
|
||||
if (!validToken)
|
||||
return null;
|
||||
return payload;
|
||||
if (DefaultAuthProvider == null) throw new Exception("Default auth provider isn't specified");
|
||||
return DefaultAuthProvider.TestToken(token);
|
||||
}
|
||||
|
||||
public void AddAuthProvider(IAuthProvider provider)
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@ -15,7 +17,7 @@ namespace Zirconium.Core.Models
|
||||
public string From { get; set; }
|
||||
|
||||
[JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string To { get; set; }
|
||||
public string[] To { get; set; }
|
||||
|
||||
[JsonProperty("ok")]
|
||||
public bool Ok { get; set; }
|
||||
@ -26,28 +28,31 @@ namespace Zirconium.Core.Models
|
||||
[JsonProperty("payload")]
|
||||
public IDictionary<string, object> Payload { get; set; }
|
||||
|
||||
public BaseMessage() { }
|
||||
|
||||
public BaseMessage(BaseMessage message, bool reply)
|
||||
{
|
||||
public BaseMessage() {
|
||||
Payload = new Dictionary<string, object>();
|
||||
ID = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public BaseMessage(BaseMessage message, bool reply) : this()
|
||||
{
|
||||
if (message != null)
|
||||
{
|
||||
ID = message.ID;
|
||||
MessageType = message.MessageType;
|
||||
if (reply)
|
||||
{
|
||||
From = message.To;
|
||||
To = message.From;
|
||||
// TODO probably need to fix it
|
||||
From = message.To.First();
|
||||
To = new string[] { message.From };
|
||||
}
|
||||
else
|
||||
{
|
||||
From = message.From;
|
||||
To = message.To;
|
||||
AuthToken = message.AuthToken;
|
||||
}
|
||||
|
||||
Ok = message.Ok;
|
||||
AuthToken = message.AuthToken;
|
||||
Payload = message.Payload;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace Zirconium.Core.Models
|
||||
public class Session
|
||||
{
|
||||
public string LastTokenHash { get; set; }
|
||||
public JWTPayload LastTokenPayload { get; set; }
|
||||
public SessionAuthData LastTokenPayload { get; set; }
|
||||
public IPAddress ClientAddress { get; set; }
|
||||
public ConnectionHandler ConnectionHandler { get; set; }
|
||||
}
|
||||
|
@ -3,13 +3,15 @@ namespace Zirconium.Core.Plugins.Interfaces
|
||||
public interface IAuthProvider
|
||||
{
|
||||
// Method for checking validity of access token in each message
|
||||
bool TestToken(string token, JWTPayload payload);
|
||||
SessionAuthData TestToken(string token);
|
||||
|
||||
// Method for testing password when logging in
|
||||
bool TestPassword(string username, string pass);
|
||||
|
||||
// User registration logic
|
||||
void CreateUser(string username, string pass);
|
||||
|
||||
string CreateAuthToken(string entityID, string deviceID, long tokenExpirationMillis);
|
||||
string GetAuthProviderName();
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@ namespace Zirconium.Core
|
||||
}
|
||||
if (session.LastTokenHash != hash)
|
||||
{
|
||||
JWTPayload tokenPayload;
|
||||
SessionAuthData tokenPayload;
|
||||
try
|
||||
{
|
||||
tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken);
|
||||
|
@ -1,13 +1,8 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Zirconium.Core
|
||||
{
|
||||
public class JWTPayload
|
||||
public class SessionAuthData
|
||||
{
|
||||
[JsonProperty("entityID")]
|
||||
public string EntityID { get; set; }
|
||||
|
||||
[JsonProperty("deviceID")]
|
||||
public string DeviceID { get; set; }
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@
|
||||
<PackageReference Include="Colorful.Console" Version="1.2.10" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="websocketsharp.core" Version="1.0.0" />
|
||||
<PackageReference Include="JWT" Version="7.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.0" />
|
||||
<PackageReference Include="Nett" Version="0.15.0" />
|
||||
|
@ -10,5 +10,6 @@
|
||||
</ProjectReference>
|
||||
|
||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.2.1" />
|
||||
<PackageReference Include="JWT" Version="7.2.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -4,6 +4,11 @@ using MongoDB.Driver;
|
||||
using Zirconium.Core;
|
||||
using Zirconium.Core.Plugins.Interfaces;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using JWT.Algorithms;
|
||||
using JWT.Builder;
|
||||
using System;
|
||||
using Zirconium.Utils;
|
||||
|
||||
namespace DefaultAuthProvider
|
||||
{
|
||||
@ -17,7 +22,8 @@ namespace DefaultAuthProvider
|
||||
public void Initialize(IPluginHostAPI hostModuleAPI)
|
||||
{
|
||||
var db = hostModuleAPI.GetRawDatabase();
|
||||
hostModuleAPI.ProvideAuth(new DefaultAuthProvider(db));
|
||||
var jwtSecret = hostModuleAPI.GetSettings(this)["JWTSecret"];
|
||||
hostModuleAPI.ProvideAuth(new DefaultAuthProvider(db, jwtSecret));
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,10 +40,12 @@ namespace DefaultAuthProvider
|
||||
|
||||
private IMongoDatabase _db;
|
||||
private IMongoCollection<User> usersCol;
|
||||
private string jwtSecret;
|
||||
|
||||
public DefaultAuthProvider(IMongoDatabase db)
|
||||
public DefaultAuthProvider(IMongoDatabase db, string jwtSecret)
|
||||
{
|
||||
this._db = db;
|
||||
this.jwtSecret = jwtSecret;
|
||||
this.usersCol = db.GetCollection<User>("default_auth_data");
|
||||
_createUsernameUniqueIndex();
|
||||
}
|
||||
@ -71,7 +79,8 @@ namespace DefaultAuthProvider
|
||||
{
|
||||
var filter = Builders<User>.Filter.Eq("Username", username);
|
||||
var user = usersCol.Find(filter).FirstOrDefault();
|
||||
if (user == null) {
|
||||
if (user == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var valid = PasswordHasher.VerifyHash(pass, user.Salt, user.Password);
|
||||
@ -79,9 +88,28 @@ namespace DefaultAuthProvider
|
||||
return valid;
|
||||
}
|
||||
|
||||
public bool TestToken(string token, JWTPayload payload)
|
||||
public SessionAuthData TestToken(string token)
|
||||
{
|
||||
return true; // TODO add enchanced token validation later
|
||||
var jsonPayload = new JwtBuilder()
|
||||
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
||||
.WithSecret(this.jwtSecret)
|
||||
.MustVerifySignature()
|
||||
.Decode(token);
|
||||
var payload = JsonConvert.DeserializeObject<SessionAuthData>(jsonPayload);
|
||||
return payload; // TODO add enchanced token validation
|
||||
}
|
||||
|
||||
public string CreateAuthToken(string entityID, string deviceID, long tokenExpirationMillis)
|
||||
{
|
||||
SessionAuthData payload = new SessionAuthData();
|
||||
payload.DeviceID = deviceID;
|
||||
payload.EntityID = entityID;
|
||||
return new JwtBuilder()
|
||||
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
||||
.WithSecret(this.jwtSecret)
|
||||
.AddClaim("exp", DateTimeOffset.UtcNow.AddMilliseconds(tokenExpirationMillis).ToUnixTimeSeconds())
|
||||
.AddClaims(payload.ToDictionary())
|
||||
.Encode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user