From 898d603b8d99177a1e5320a64bac5fabc0dba4c6 Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Mon, 8 Mar 2021 16:06:12 +0300 Subject: [PATCH] Fully refactor authorization architecture (make it more modular) --- src/Zirconium/Core/App.cs | 6 +- src/Zirconium/Core/AuthManager.cs | 50 ------------- src/Zirconium/Core/AuthProviderManager.cs | 30 ++++++++ src/Zirconium/Core/ConnectionHandler.cs | 7 +- .../Authorization/AuthorizationRequest.cs | 14 ++++ .../Authorization/AuthorizationResponse.cs | 13 ++++ src/Zirconium/Core/Models/BaseMessage.cs | 13 ++-- src/Zirconium/Core/Models/Session.cs | 2 +- .../Core/Plugins/Interfaces/IAuthProvider.cs | 15 ++-- .../Core/Plugins/Interfaces/IPluginHostAPI.cs | 2 - src/Zirconium/Core/Plugins/PluginHostAPI.cs | 15 +--- src/Zirconium/Core/Plugins/PluginManager.cs | 5 +- src/Zirconium/Core/Router.cs | 36 ++------- src/Zirconium/Utils/ObjectExtensions.cs | 2 +- src/Zirconium/Utils/OtherUtils.cs | 16 +++- src/ZirconiumPlugins/ChatSubsystem/Plugin.cs | 4 +- .../DefaultAuthProvider/LoginPassFields.cs | 10 +++ .../DefaultAuthProvider/Plugin.cs | 75 +++++++++++++++---- .../InBandLogin/Handlers/LoginC2SHandler.cs | 35 ++++++--- .../Handlers/RegisterC2SHandler.cs | 8 +- .../InBandLogin/PayloadModels.cs | 3 - 21 files changed, 203 insertions(+), 158 deletions(-) delete mode 100644 src/Zirconium/Core/AuthManager.cs create mode 100644 src/Zirconium/Core/AuthProviderManager.cs create mode 100644 src/Zirconium/Core/Models/Authorization/AuthorizationRequest.cs create mode 100644 src/Zirconium/Core/Models/Authorization/AuthorizationResponse.cs create mode 100644 src/ZirconiumPlugins/DefaultAuthProvider/LoginPassFields.cs diff --git a/src/Zirconium/Core/App.cs b/src/Zirconium/Core/App.cs index a534cd3..be50aec 100644 --- a/src/Zirconium/Core/App.cs +++ b/src/Zirconium/Core/App.cs @@ -13,7 +13,7 @@ namespace Zirconium.Core public Router Router { get; } public PluginManager PluginManager { get; } public IPluginHostAPI PluginHostAPI { get; } - public AuthManager AuthManager { get; } + public AuthProviderManager AuthProviderManager { get; } private WebSocketServer _websocketServer; public DatabaseConnector Database { get; private set; } @@ -25,11 +25,11 @@ namespace Zirconium.Core SessionManager = new SessionManager(); Router = new Router(this); PluginHostAPI = new PluginHostAPI(this, Router); - AuthManager = new AuthManager(this); + AuthProviderManager = new AuthProviderManager(this); Database = new DatabaseConnector(this); PluginManager = new PluginManager(PluginHostAPI); PluginManager.LoadPlugins(config.PluginsDirPath, config.EnabledPlugins); - AuthManager.SetDefaultAuthProvider(); + AuthProviderManager.SetDefaultAuthProvider(); Log.Info("Zirconium is initialized successfully"); } diff --git a/src/Zirconium/Core/AuthManager.cs b/src/Zirconium/Core/AuthManager.cs deleted file mode 100644 index d7f9e3f..0000000 --- a/src/Zirconium/Core/AuthManager.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System; -using Zirconium.Core.Plugins.Interfaces; -using System.Linq; - -namespace Zirconium.Core -{ - public class AuthManager - { - private App _app; - private string _secretString; - private const long DEFAULT_TOKEN_EXPIRATION_TIME_HOURS = 24 * 3600000; - private IList _authProviders; - public IAuthProvider DefaultAuthProvider { get; private set; } - - public AuthManager(App app) - { - _app = app; - _authProviders = new List(); - DefaultAuthProvider = null; - _secretString = Guid.NewGuid().ToString(); - } - - public string CreateToken(string entityID, string deviceID, long tokenExpirationMillis) - { - 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) - { - return CreateToken(entityID, deviceID, DEFAULT_TOKEN_EXPIRATION_TIME_HOURS); - } - - public SessionAuthData ValidateToken(string token) - { - if (DefaultAuthProvider == null) throw new Exception("Default auth provider isn't specified"); - return DefaultAuthProvider.TestToken(token); - } - - public void AddAuthProvider(IAuthProvider provider) - { - _authProviders.Add(provider); - } - - public void SetDefaultAuthProvider() { - DefaultAuthProvider = _authProviders.Where(x => x.GetAuthProviderName() == _app.Config.AuthenticationProvider).FirstOrDefault(); - } - } -} \ No newline at end of file diff --git a/src/Zirconium/Core/AuthProviderManager.cs b/src/Zirconium/Core/AuthProviderManager.cs new file mode 100644 index 0000000..a9f7d87 --- /dev/null +++ b/src/Zirconium/Core/AuthProviderManager.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System; +using Zirconium.Core.Plugins.Interfaces; +using System.Linq; + +namespace Zirconium.Core +{ + public class AuthProviderManager + { + private App _app; + private IList _authProviders; + public IAuthProvider DefaultAuthProvider { get; private set; } + + public AuthProviderManager(App app) + { + _app = app; + _authProviders = new List(); + DefaultAuthProvider = null; + } + + public void AddAuthProvider(IAuthProvider provider) + { + _authProviders.Add(provider); + } + + public void SetDefaultAuthProvider() { + DefaultAuthProvider = _authProviders.FirstOrDefault(x => x.GetAuthProviderName() == _app.Config.AuthenticationProvider); + } + } +} \ No newline at end of file diff --git a/src/Zirconium/Core/ConnectionHandler.cs b/src/Zirconium/Core/ConnectionHandler.cs index f156a4c..0987283 100644 --- a/src/Zirconium/Core/ConnectionHandler.cs +++ b/src/Zirconium/Core/ConnectionHandler.cs @@ -23,7 +23,6 @@ namespace Zirconium.Core _app.SessionManager.DeleteSession(ID); Log.Info($"Connection {ID} was closed (reason: {e.Reason})"); // TODO implement closing connection - } protected override void OnError(ErrorEventArgs e) @@ -45,7 +44,7 @@ namespace Zirconium.Core var errMsg = OtherUtils.GenerateProtocolError( null, "parseError", - $"Server cannot parse this message yet because it is not JSON", + $"Server cannot parse this message because it is not JSON", new Dictionary() ); errMsg.From = _app.Config.ServerID; @@ -73,8 +72,8 @@ namespace Zirconium.Core var session = new Session(); session.ClientAddress = ip; session.ConnectionHandler = this; - _app.SessionManager.AddSession(this.ID, session); - Log.Info($"Connection {this.ID} was created"); + _app.SessionManager.AddSession(ID, session); + Log.Info($"Connection {ID} was created"); } public void SendMessage(string message) diff --git a/src/Zirconium/Core/Models/Authorization/AuthorizationRequest.cs b/src/Zirconium/Core/Models/Authorization/AuthorizationRequest.cs new file mode 100644 index 0000000..f47f11e --- /dev/null +++ b/src/Zirconium/Core/Models/Authorization/AuthorizationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Zirconium.Core.Models.Authorization +{ + public class AuthorizationRequest + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("fields")] + public IDictionary Fields { get; set; } + } +} \ No newline at end of file diff --git a/src/Zirconium/Core/Models/Authorization/AuthorizationResponse.cs b/src/Zirconium/Core/Models/Authorization/AuthorizationResponse.cs new file mode 100644 index 0000000..c88d231 --- /dev/null +++ b/src/Zirconium/Core/Models/Authorization/AuthorizationResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Zirconium.Core.Models.Authorization +{ + public class AuthorizationResponse + { + [JsonProperty("token")] + public string Token; + + [JsonProperty("deviceID")] + public string DeviceID { get; set; } + } +} \ No newline at end of file diff --git a/src/Zirconium/Core/Models/BaseMessage.cs b/src/Zirconium/Core/Models/BaseMessage.cs index 03be79f..bee1333 100644 --- a/src/Zirconium/Core/Models/BaseMessage.cs +++ b/src/Zirconium/Core/Models/BaseMessage.cs @@ -22,10 +22,7 @@ namespace Zirconium.Core.Models [JsonProperty("ok")] public bool Ok { get; set; } - [JsonProperty("authToken", NullValueHandling = NullValueHandling.Ignore)] - public string AuthToken { get; set; } - - [JsonProperty("payload")] + [JsonProperty("payload", NullValueHandling = NullValueHandling.Ignore)] public IDictionary Payload { get; set; } public BaseMessage() { @@ -33,6 +30,11 @@ namespace Zirconium.Core.Models ID = Guid.NewGuid().ToString(); } + public BaseMessage(string type) : this() + { + MessageType = type; + } + public BaseMessage(BaseMessage message, bool reply) : this() { if (message != null) @@ -43,13 +45,12 @@ namespace Zirconium.Core.Models { // TODO probably need to fix it From = message.To.First(); - To = new string[] { message.From }; + To = new[] { message.From }; } else { From = message.From; To = message.To; - AuthToken = message.AuthToken; } Ok = message.Ok; diff --git a/src/Zirconium/Core/Models/Session.cs b/src/Zirconium/Core/Models/Session.cs index 414f03a..fc2ea5d 100644 --- a/src/Zirconium/Core/Models/Session.cs +++ b/src/Zirconium/Core/Models/Session.cs @@ -4,7 +4,7 @@ namespace Zirconium.Core.Models { public class Session { - public SessionAuthData LastTokenPayload { get; set; } + public SessionAuthData AuthData { get; set; } public IPAddress ClientAddress { get; set; } public ConnectionHandler ConnectionHandler { get; set; } } diff --git a/src/Zirconium/Core/Plugins/Interfaces/IAuthProvider.cs b/src/Zirconium/Core/Plugins/Interfaces/IAuthProvider.cs index a4cbcef..97f764a 100644 --- a/src/Zirconium/Core/Plugins/Interfaces/IAuthProvider.cs +++ b/src/Zirconium/Core/Plugins/Interfaces/IAuthProvider.cs @@ -1,17 +1,18 @@ +using System.Collections.Generic; +using Zirconium.Core.Models; +using Zirconium.Core.Models.Authorization; + namespace Zirconium.Core.Plugins.Interfaces { public interface IAuthProvider { - // Method for checking validity of access token in each message - SessionAuthData TestToken(string token); - - // Method for testing password when logging in - bool TestPassword(string username, string pass); + (SessionAuthData, AuthorizationResponse) TestAuthFields(IDictionary fields); + + EntityID GetEntityID(IDictionary fields); // User registration logic void CreateUser(string username, string pass); - - string CreateAuthToken(string entityID, string deviceID, long tokenExpirationMillis); string GetAuthProviderName(); + string[] GetAuthSupportedMethods(); } } \ No newline at end of file diff --git a/src/Zirconium/Core/Plugins/Interfaces/IPluginHostAPI.cs b/src/Zirconium/Core/Plugins/Interfaces/IPluginHostAPI.cs index ddb8164..d17e754 100644 --- a/src/Zirconium/Core/Plugins/Interfaces/IPluginHostAPI.cs +++ b/src/Zirconium/Core/Plugins/Interfaces/IPluginHostAPI.cs @@ -11,8 +11,6 @@ namespace Zirconium.Core.Plugins.Interfaces void Unhook(IC2SMessageHandler handler); void UnhookCoreEvent(ICoreEventHandler handler); void FireEvent(CoreEvent coreEvent); - string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis); - string GenerateAuthToken(string entityID, string deviceID); string[] GetServerDomains(); string GetServerID(); void SendMessage(Session session, BaseMessage message); diff --git a/src/Zirconium/Core/Plugins/PluginHostAPI.cs b/src/Zirconium/Core/Plugins/PluginHostAPI.cs index f6e8b8b..d155504 100644 --- a/src/Zirconium/Core/Plugins/PluginHostAPI.cs +++ b/src/Zirconium/Core/Plugins/PluginHostAPI.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Threading.Tasks; using MongoDB.Driver; @@ -27,7 +26,7 @@ namespace Zirconium.Core.Plugins } public void ProvideAuth(IAuthProvider provider) { - _app.AuthManager.AddAuthProvider(provider); + _app.AuthProviderManager.AddAuthProvider(provider); } public void FireEvent(CoreEvent coreEvent) @@ -35,11 +34,6 @@ namespace Zirconium.Core.Plugins _router.RouteCoreEvent(coreEvent); } - public string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis) - { - return _app.AuthManager.CreateToken(entityID, deviceID, tokenExpirationMillis); - } - public string[] GetServerDomains() { return _app.Config.ServerDomains; @@ -105,12 +99,7 @@ namespace Zirconium.Core.Plugins public IAuthProvider GetAuthProvider() { - return _app.AuthManager.DefaultAuthProvider; - } - - public string GenerateAuthToken(string entityID, string deviceID) - { - return _app.AuthManager.CreateToken(entityID, deviceID); + return _app.AuthProviderManager.DefaultAuthProvider; } } } \ No newline at end of file diff --git a/src/Zirconium/Core/Plugins/PluginManager.cs b/src/Zirconium/Core/Plugins/PluginManager.cs index 339c524..edbb4b8 100644 --- a/src/Zirconium/Core/Plugins/PluginManager.cs +++ b/src/Zirconium/Core/Plugins/PluginManager.cs @@ -7,6 +7,7 @@ using Log4Sharp; using McMaster.NETCore.Plugins; using MongoDB.Driver; using Zirconium.Core.Models; +using Zirconium.Core.Models.Authorization; using Zirconium.Core.Plugins.Interfaces; using Zirconium.Core.Plugins.IPC; using Zirconium.Utils; @@ -76,7 +77,9 @@ namespace Zirconium.Core.Plugins typeof(BaseMessage), typeof(CoreEvent), typeof(ExportedIPCMethodAttribute), - typeof(IMongoDatabase) + typeof(IMongoDatabase), + typeof(AuthorizationRequest), + typeof(AuthorizationResponse) }, config => config.PreferSharedTypes = true ); diff --git a/src/Zirconium/Core/Router.cs b/src/Zirconium/Core/Router.cs index 0608c7f..bcbe887 100644 --- a/src/Zirconium/Core/Router.cs +++ b/src/Zirconium/Core/Router.cs @@ -36,45 +36,23 @@ namespace Zirconium.Core new Dictionary() ); msg.From = _app.Config.ServerID; - var serializedMsg = JsonConvert.SerializeObject(msg); - session.ConnectionHandler.SendMessage(serializedMsg); + session.ConnectionHandler.SendMessage(msg); return; } var handlerTasks = new List(); foreach (var h in handlers) { - if (h.IsAuthorizationRequired()) + if (h.IsAuthorizationRequired() && session.AuthData == null) { - SessionAuthData tokenPayload; - try - { - tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken); - } - catch (Exception e) - { - Log.Warning(e.Message); - var errorMsg = OtherUtils.GenerateProtocolError( - message, - "unauthorized", - "Unauthorized access", - new Dictionary() - ); - errorMsg.From = _app.Config.ServerID; - var serializedMsg = JsonConvert.SerializeObject(errorMsg); - - session.LastTokenPayload = null; - session.ConnectionHandler.SendMessage(serializedMsg); - return; - } - session.LastTokenPayload = tokenPayload; + session.ConnectionHandler.SendMessage(OtherUtils.GenerateUnauthorizedError(message, _app.Config.ServerID)); + return; } - - var task = Task.Run(() => + + handlerTasks.Add(Task.Run(() => { // probably need to wrap whole foreach body, not only HandleMessage call - need to investigate h.HandleMessage(session, message); - }); - handlerTasks.Add(task); + })); } try { diff --git a/src/Zirconium/Utils/ObjectExtensions.cs b/src/Zirconium/Utils/ObjectExtensions.cs index 90328a1..96c0957 100644 --- a/src/Zirconium/Utils/ObjectExtensions.cs +++ b/src/Zirconium/Utils/ObjectExtensions.cs @@ -81,7 +81,7 @@ namespace Zirconium.Utils public static TValue GetValueOrDefault(this IDictionary dictionary, TKey key, - TValue defaultValue) + TValue defaultValue = default) { TValue value; return dictionary.TryGetValue(key, out value) ? value : defaultValue; diff --git a/src/Zirconium/Utils/OtherUtils.cs b/src/Zirconium/Utils/OtherUtils.cs index acf7f30..5b32305 100644 --- a/src/Zirconium/Utils/OtherUtils.cs +++ b/src/Zirconium/Utils/OtherUtils.cs @@ -6,7 +6,7 @@ namespace Zirconium.Utils { public static class OtherUtils { - public static BaseMessage GenerateProtocolError(BaseMessage parentMessage, string errCode, string errText, IDictionary errPayload) + public static BaseMessage GenerateProtocolError(BaseMessage parentMessage, string errCode, string errText, IDictionary errPayload = null) { ProtocolError err = new ProtocolError(); err.ErrCode = errCode; @@ -21,5 +21,17 @@ namespace Zirconium.Utils msg.Payload = err.ToDictionary(); return msg; } + + public static BaseMessage GenerateUnauthorizedError(BaseMessage replyTo, string serverID) + { + var msg = GenerateProtocolError( + replyTo, + "unauthorized", + "Unauthorized access", + new Dictionary() + ); + msg.From = serverID; + return msg; + } } -} \ No newline at end of file +} diff --git a/src/ZirconiumPlugins/ChatSubsystem/Plugin.cs b/src/ZirconiumPlugins/ChatSubsystem/Plugin.cs index bf38c03..829af48 100644 --- a/src/ZirconiumPlugins/ChatSubsystem/Plugin.cs +++ b/src/ZirconiumPlugins/ChatSubsystem/Plugin.cs @@ -83,7 +83,7 @@ namespace ChatSubsystem var recipientSession = pluginHostAPI.GetSessionManager() .GetSessions() .Select(x => x.Value) - .Where(x => x.LastTokenPayload.EntityID.Where(x => x == message.To.First()).FirstOrDefault() != null) + .Where(x => x.AuthData.EntityID.Where(x => x == message.To.First()).FirstOrDefault() != null) .FirstOrDefault(); if (recipientSession == null) @@ -93,7 +93,7 @@ namespace ChatSubsystem } var msgForRecipient = new BaseMessage(); - msgForRecipient.From = session.LastTokenPayload.EntityID.First(); + msgForRecipient.From = session.AuthData.EntityID.First(); msgForRecipient.MessageType = "urn:cadmium:chats:message"; respPayload.Type = receivedMessage.Type; respPayload.Content = receivedMessage.Content; diff --git a/src/ZirconiumPlugins/DefaultAuthProvider/LoginPassFields.cs b/src/ZirconiumPlugins/DefaultAuthProvider/LoginPassFields.cs new file mode 100644 index 0000000..8383d1d --- /dev/null +++ b/src/ZirconiumPlugins/DefaultAuthProvider/LoginPassFields.cs @@ -0,0 +1,10 @@ +using Zirconium.Core.Models.Authorization; + +namespace DefaultAuthProvider +{ + public class LoginPassFields + { + public string Username { get; set; } + public string Password { get; set; } + } +} \ No newline at end of file diff --git a/src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs b/src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs index e0f0ff7..aff25c8 100644 --- a/src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs +++ b/src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs @@ -8,6 +8,9 @@ using Newtonsoft.Json; using JWT.Algorithms; using JWT.Builder; using System; +using System.Collections.Generic; +using Zirconium.Core.Models; +using Zirconium.Core.Models.Authorization; using Zirconium.Utils; namespace DefaultAuthProvider @@ -23,12 +26,14 @@ namespace DefaultAuthProvider { var db = pluginHost.GetRawDatabase(); var jwtSecret = pluginHost.GetSettings(this)["JWTSecret"]; - pluginHost.ProvideAuth(new DefaultAuthProvider(db, jwtSecret)); + pluginHost.ProvideAuth(new DefaultAuthProvider(db, jwtSecret, pluginHost.GetServerID())); } } public class DefaultAuthProvider : IAuthProvider { + private const long DEFAULT_TOKEN_EXPIRATION_TIME_HOURS = 24 * 3600000; + public class User { [BsonId] @@ -41,11 +46,13 @@ namespace DefaultAuthProvider private IMongoDatabase _db; private IMongoCollection usersCol; private string jwtSecret; + private string _serverID; - public DefaultAuthProvider(IMongoDatabase db, string jwtSecret) + public DefaultAuthProvider(IMongoDatabase db, string jwtSecret, string serverID) { this._db = db; this.jwtSecret = jwtSecret; + this._serverID = serverID; this.usersCol = db.GetCollection("default_auth_data"); _createUsernameUniqueIndex(); } @@ -59,22 +66,50 @@ namespace DefaultAuthProvider usersCol.Indexes.CreateOne(createIndexModel); } + public EntityID GetEntityID(IDictionary fieldsDict) + { + var fields = fieldsDict.ToObject(); + return new EntityID('@', fields.Username, _serverID); + } + public void CreateUser(string username, string pass) { var user = new User(); user.Username = username; // TODO add check on bad chars var hashed = PasswordHasher.CreatePasswordHash(pass); - System.GC.Collect(); + GC.Collect(); user.Password = hashed.Item1; user.Salt = hashed.Item2; _db.GetCollection("default_auth_data").InsertOne(user); } - public string GetAuthProviderName() + public (SessionAuthData, AuthorizationResponse) TestAuthFields(IDictionary fieldsDict) { - return "default"; + if (fieldsDict.GetValueOrDefault("token") == null) + { + var fields = fieldsDict.ToObject(); + bool valid = TestPassword(fields.Username, fields.Password); + if (valid) + { + // TODO Fix device system + var tokenData = CreateAuthToken(GetEntityID(fieldsDict).ToString(), "ABCDEF", DEFAULT_TOKEN_EXPIRATION_TIME_HOURS); + var res = new AuthorizationResponse() + { + Token = tokenData.Item1 + }; + return (tokenData.Item2, res); + } + + return (null, null); + } + + return (TestToken(fieldsDict["token"]), null); } + public string GetAuthProviderName() => "default"; + + public string[] GetAuthSupportedMethods() => new[] { "urn:cadmium:auth:login_password", "urn:cadmium:auth:token" }; + public bool TestPassword(string username, string pass) { var filter = Builders.Filter.Eq("Username", username); @@ -84,32 +119,40 @@ namespace DefaultAuthProvider return false; } var valid = PasswordHasher.VerifyHash(pass, user.Salt, user.Password); - System.GC.Collect(); + GC.Collect(); return valid; } public SessionAuthData TestToken(string token) { - var jsonPayload = new JwtBuilder() - .WithAlgorithm(new HMACSHA256Algorithm()) // symmetric - .WithSecret(this.jwtSecret) - .MustVerifySignature() - .Decode(token); - var payload = JsonConvert.DeserializeObject(jsonPayload); - return payload; // TODO add enchanced token validation + try + { + var jsonPayload = new JwtBuilder() + .WithAlgorithm(new HMACSHA256Algorithm()) // symmetric + .WithSecret(jwtSecret) + .MustVerifySignature() + .Decode(token); + var payload = JsonConvert.DeserializeObject(jsonPayload); + if (payload == null) payload = new SessionAuthData(); + return payload; // TODO add enchanced token validation + } + catch + { + return null; + } } - public string CreateAuthToken(string entityID, string deviceID, long tokenExpirationMillis) + private (string, SessionAuthData) CreateAuthToken(string entityID, string deviceID, long tokenExpirationMillis) { SessionAuthData payload = new SessionAuthData(); payload.DeviceID = deviceID; payload.EntityID = new string[] { entityID }; - return new JwtBuilder() + return (new JwtBuilder() .WithAlgorithm(new HMACSHA256Algorithm()) // symmetric .WithSecret(this.jwtSecret) .AddClaim("exp", DateTimeOffset.UtcNow.AddMilliseconds(tokenExpirationMillis).ToUnixTimeSeconds()) .AddClaims(payload.ToDictionary()) - .Encode(); + .Encode(), payload); } } } diff --git a/src/ZirconiumPlugins/InBandLogin/Handlers/LoginC2SHandler.cs b/src/ZirconiumPlugins/InBandLogin/Handlers/LoginC2SHandler.cs index 4b9f631..0797212 100644 --- a/src/ZirconiumPlugins/InBandLogin/Handlers/LoginC2SHandler.cs +++ b/src/ZirconiumPlugins/InBandLogin/Handlers/LoginC2SHandler.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Linq; using Zirconium.Core.Models; +using Zirconium.Core.Models.Authorization; using Zirconium.Core.Plugins.Interfaces; using Zirconium.Utils; @@ -7,7 +9,8 @@ namespace InBandLogin.Handlers { public class LoginC2SHandler : IC2SMessageHandler { - private const string errID = "invalid_creds"; + private const string errID = "urn:cadmium:auth:invalid"; + private const string invalidAuthType = "urn:cadmium:auth:invalid_type"; private readonly IPluginHostAPI _pluginHost; public LoginC2SHandler(IPluginHostAPI pluginHostApi) @@ -22,31 +25,41 @@ namespace InBandLogin.Handlers public string GetHandlingMessageType() { - return "profile:login"; + return "urn:cadmium:auth"; } public void HandleMessage(Session session, BaseMessage message) { - var pObj = message.Payload.ToObject(); + var pObj = message.Payload.ToObject(); var authProvider = _pluginHost.GetAuthProvider(); - if (authProvider.TestPassword(pObj.Username, pObj.Password)) + if (!authProvider.GetAuthSupportedMethods().Contains(pObj.Type)) + { + var reply = OtherUtils.GenerateProtocolError( + message, + invalidAuthType, + "auth type is invalid" + ); + session.ConnectionHandler.SendMessage(reply); + return; + } + var authData = authProvider.TestAuthFields(pObj.Fields); + if (authData.Item1 != null) { BaseMessage reply = new BaseMessage(message, true); - var p = new LoginResponsePayload(); - string deviceID = "ABCDEF"; // TODO fix device id system - p.AuthToken = _pluginHost.GenerateAuthToken($"@{pObj.Username}@{_pluginHost.GetServerID()}", deviceID); - p.DeviceID = deviceID; - reply.Payload = p.ToDictionary(); + if (authData.Item2 != null) + { + reply.Payload = authData.Item2.ToDictionary(); + } reply.Ok = true; session.ConnectionHandler.SendMessage(reply); + session.AuthData = authData.Item1; } else { var reply = OtherUtils.GenerateProtocolError( message, errID, - "Username/password isn't valid", - new Dictionary() + "auth credentials isn't valid" ); session.ConnectionHandler.SendMessage(reply); } diff --git a/src/ZirconiumPlugins/InBandLogin/Handlers/RegisterC2SHandler.cs b/src/ZirconiumPlugins/InBandLogin/Handlers/RegisterC2SHandler.cs index 1400c1e..4aede43 100644 --- a/src/ZirconiumPlugins/InBandLogin/Handlers/RegisterC2SHandler.cs +++ b/src/ZirconiumPlugins/InBandLogin/Handlers/RegisterC2SHandler.cs @@ -22,7 +22,7 @@ namespace InBandLogin.Handlers public string GetHandlingMessageType() { - return "profile:register"; + return "urn:cadmium:register"; } public void HandleMessage(Session session, BaseMessage message) @@ -62,12 +62,6 @@ namespace InBandLogin.Handlers BaseMessage reply = new BaseMessage(message, true); var p = new RegisterResponsePayload(); p.UserID = $"@{pObj.Username}@{_pluginHost.GetServerID()}"; - if (pObj.LoginOnSuccess) - { - string deviceID = "ABCDEF"; // TODO fix device id system - p.AuthToken = _pluginHost.GenerateAuthToken($"@{pObj.Username}@{_pluginHost.GetServerID()}", deviceID); - p.DeviceID = deviceID; - } reply.Payload = p.ToDictionary(); reply.Ok = true; diff --git a/src/ZirconiumPlugins/InBandLogin/PayloadModels.cs b/src/ZirconiumPlugins/InBandLogin/PayloadModels.cs index 77c84c6..4e81866 100644 --- a/src/ZirconiumPlugins/InBandLogin/PayloadModels.cs +++ b/src/ZirconiumPlugins/InBandLogin/PayloadModels.cs @@ -27,9 +27,6 @@ namespace InBandLogin [JsonProperty("password")] public string Password { get; set; } - - [JsonProperty("loginOnSuccess")] - public bool LoginOnSuccess { get; set; } } class RegisterResponsePayload