Пример #1
0
        public async Task <UserRefToken> GetUserRefToken(IWebRequest req)
        {
            var          authentication = req.GetAuthenticationHeaderValue();
            UserRefToken userRefToken   = await this.AuthenticateAsync(authentication?.Scheme, authentication?.Parameter) as UserRefToken;

            if (userRefToken == null)
            {
                throw new UnauthorizedException();
            }
            return(userRefToken);
        }
        /// <summary>
        /// Validates the auth token id returning an <see cref="AuthToken"/> instance
        /// </summary>
        /// <param name="authType"></param>
        /// <param name="authValue"></param>
        /// <returns>An <see cref="AuthToken"/> instance</returns>
        public async Task <AuthToken> AuthenticateAsync(string authType, string authValue)
        {
            var authTokenFieldList = new List <string>();

            if (!string.IsNullOrEmpty(this.authTokenTableIdFieldName))
            {
                authTokenFieldList.Add($"{ this.authTokenTableIdFieldName}");
            }
            if (!string.IsNullOrEmpty(this.authTokenTableUserIdFieldName))
            {
                authTokenFieldList.Add($"{ this.authTokenTableUserIdFieldName}");
            }
            if (!string.IsNullOrEmpty(this.authTokenTableExpiresAtFieldName))
            {
                authTokenFieldList.Add($"{ this.authTokenTableExpiresAtFieldName}");
            }

            var userFieldList = new List <string>();

            if (!string.IsNullOrEmpty(this.userTableAccountIdFieldName))
            {
                userFieldList.Add($"{ this.userTableAccountIdFieldName}");
            }
            if (!string.IsNullOrEmpty(this.userTableUsernameFieldName))
            {
                userFieldList.Add($"{ this.userTableUsernameFieldName}");
            }
            if (!string.IsNullOrEmpty(this.userTableRoleFieldName))
            {
                userFieldList.Add($"{ this.userTableRoleFieldName}");
            }

            Dict result;

            if (this.database.CanJoin)
            {
                var fieldList = new List <List <string> > {
                    authTokenFieldList.Select(x => $"at.{x}").ToList(), userFieldList.Select(x => $"u.{x}").ToList()
                }.SelectMany(x => x);
                var sql = $"SELECT {string.Join(",", fieldList)} FROM {this.authTokenTableName} at INNER JOIN {this.userTableName} u ON at.{this.authTokenTableUserIdFieldName}=u.{this.userTableIdFieldName} WHERE at.{authTokenTableIdFieldName}=@authTokenId";
                result = await this.database.SelectRowAsync(sql, new {
                    authTokenId = authValue
                });
            }
            else
            {
                if (!string.IsNullOrEmpty(this.authTokenTableUserIdFieldName))
                {
                    authTokenFieldList.Add($"{ this.authTokenTableUserIdFieldName}");
                }
                var authTokenSql = $"SELECT {string.Join(",", authTokenFieldList)} FROM {this.authTokenTableName} WHERE {authTokenTableIdFieldName}=@authTokenId";
                result = await this.database.SelectRowAsync(authTokenSql, new {
                    authTokenId = authValue
                });

                if (result != null)
                {
                    var userId = result.GetAs(this.authTokenTableUserIdFieldName, "");

                    var  userSql    = $"SELECT {string.Join(",", userFieldList)} FROM {this.userTableName} WHERE {this.userTableIdFieldName}=@userId";
                    Dict userResult = await this.database.SelectRowAsync(userSql, new {
                        userId
                    });

                    result.UpdateFrom(userResult);
                }
            }
            logger.Debug($"Authenticate():authTokenDict={result}");
            if (result == null)
            {
                throw new UnauthorizedException();
            }

            var authToken = UserRefToken.FromDict(result, this.authTokenTableIdFieldName, this.authTokenTableUserIdFieldName, this.userTableUsernameFieldName, this.userTableRoleFieldName, this.userTableAccountIdFieldName, this.authTokenTableExpiresAtFieldName);

            logger.Debug($"Authenticate():authToken.expiresAt={authToken.expiresAt}");
            if (authToken.expiresAt == DateTime.MinValue || authToken.expiresAt < DateTime.Now)
            {
                throw new UnauthorizedException();
            }

            return(authToken);
        }
Пример #3
0
        /// <summary>
        /// Registers a new user
        /// </summary>
        /// <param name="input"></param>
        /// <param name="notifyData"></param>
        /// <returns></returns>
        public async Task <UserRefToken> RegisterAsync(dynamic input, Dict notifyData = null)
        {
            Dict registration = this.ConvertInputToDict(input);

            // Lookup existing user, account, and username
            string existingUserId    = registration.GetAs("user_id", (string)null);
            string existingAccountId = null;
            string existingUsername  = null;

            logger.Trace($"RegisterAsync():existingUserId={existingUserId}");
            if (!string.IsNullOrEmpty(existingUserId))
            {
                Dict row = await this.database.SelectRowAsync($"SELECT {this.userTableAccountIdFieldName}, {this.userTableUsernameFieldName} FROM {this.userTableName}", existingUserId);

                existingAccountId = row.GetAs(this.userTableAccountIdFieldName, "");
                existingUsername  = row.GetAs(this.userTableUsernameFieldName, "");
            }

            // Validate username
            string username = this.usernameFieldValidator.Validate(registration?.GetAs(this.userTableUsernameFieldName, (string)null));

            logger.Trace($"RegisterAsync():username={username}");
            if (username != existingUsername)
            {
                Dict existingUserByUsername = await this.database.SelectRowAsync(this.userTableName, new Dict {
                    { this.userTableUsernameFieldName, username }
                });

                if (existingUserByUsername != null)
                {
                    throw new Exception("Username '" + username + "' is unavailable");
                }
            }

            // Validate password
            string password = this.passwordFieldValidator.Validate(registration?.GetAs("password", (string)null));

            // Validate email and phone
            string email = this.emailFieldValidator.Validate(registration?.GetAs(this.userTableEmailFieldName, (string)null));
            string phone = this.phoneFieldValidator.Validate(registration?.GetAs(this.userTablePhoneFieldName, (string)null));

            // Validate first and last name
            string firstName = this.nameFieldValidator.Validate(registration?.GetAs(this.userTableFirstNameFieldName, (string)null));
            string lastName  = this.nameFieldValidator.Validate(registration?.GetAs(this.userTableLastNameFieldName, (string)null));

            string role = string.IsNullOrEmpty(this.userTableRoleFieldName) ? this.defaultRole : registration?.GetAs(this.userTableRoleFieldName, this.defaultRole);

            // Create salt and password hash
            string salt         = Guid.NewGuid().ToString();
            string passwordHash = $"{salt} {password}".Hash();

            // Create account
            string accountId;

            using (ITransaction transaction = await this.database.BeginTransactionAsync()) {
                if (string.IsNullOrEmpty(existingAccountId))
                {
                    var extraAccountInfo = this.getExtraAccountInfo == null ? null : this.getExtraAccountInfo(registration);
                    accountId = await transaction.InsertAsync <string>(this.accountTableName, extraAccountInfo);
                }
                else
                {
                    accountId = existingAccountId;
                }

                // Create user record
                Dict user = new Dict {
                    { this.userTableAccountIdFieldName, accountId },
                    { this.userTableUsernameFieldName, username },
                    { this.userTableSaltFieldName, salt },
                    { this.userTablePasswordHashFieldName, passwordHash },
                    { this.userTableEmailFieldName, email },
                    { this.userTablePhoneFieldName, phone },
                    { this.userTableFirstNameFieldName, firstName },
                    { this.userTableLastNameFieldName, lastName },
                };
                if (!string.IsNullOrEmpty(this.userTableRoleFieldName) && !string.IsNullOrEmpty(this.defaultRole))
                {
                    user[this.userTableRoleFieldName] = role;
                }
                Dict extraUserInfo = this.getExtraUserInfo == null ? null : this.getExtraUserInfo(registration);
                if (extraUserInfo != null)
                {
                    user.UpdateFrom(extraUserInfo);
                }

                string userId;
                if (string.IsNullOrEmpty(existingUserId))
                {
                    userId = await transaction.InsertAsync <string>(this.userTableName, user);
                }
                else
                {
                    userId = existingUserId;
                    user[this.userTableIdFieldName] = userId;
                    await transaction.UpdateAsync(this.userTableName, user);
                }

                if (this.onRegister != null)
                {
                    transaction.OnCommit(async() => {
                        var registerUser = new Dict {
                            { this.userTableIdFieldName, userId },
                            { this.userTableAccountIdFieldName, accountId },
                            { this.userTableUsernameFieldName, username },
                            { this.userTableEmailFieldName, email },
                            { this.userTablePhoneFieldName, phone },
                            { this.userTableFirstNameFieldName, firstName },
                            { this.userTableLastNameFieldName, lastName },
                        };
                        if (notifyData != null)
                        {
                            registerUser.UpdateFrom(notifyData);
                        }
                        try {
                            await this.onRegister(string.IsNullOrEmpty(existingAccountId), registerUser);
                        }
                        catch (Exception e) {
                            logger.Debug(e);
                        }
                    });
                }

                UserRefToken userRefToken = await this.CreateUserRefTokenAsync(transaction, userId, username, role, accountId);

                await transaction.CommitAsync();

                return(userRefToken);
            }
        }
Пример #4
0
        /// <summary>
        /// Call to setup a Web API with the specified <paramref name="webApi"/>
        /// </summary>
        /// <remarks>
        /// The following API URLs will be setup...
        /// <code>
        ///     GET /api/auth/check-username/{username}
        ///     GET /api/auth/check-auth-token/{id}
        ///     POST /api/auth/create-anonymous
        ///     POST /api/auth/register
        ///     POST /api/auth/login
        ///     POST /api/auth/forgot-password
        ///     POST /api/auth/reset-password
        ///     POST /api/auth/verify
        /// </code>
        /// </remarks>
        /// <param name="webApi"></param>
        /// <param name="pathPrefix">Defaults to /api/auth</param>
        public void SetupWebApi(IWebApi webApi, string pathPrefix = "/api/auth")
        {
            webApi.OnGet($"{pathPrefix}/check-username/{{username}}", async(req, res) => {
                string username = req.PathParams.GetAs("username", (string)null);
                logger.Debug($"/check-username/{username}");
                Dict user      = await this.LookupUsernameAsync(username, this.userTableIdFieldName);
                bool available = user == null;
                await res.WriteAsJsonAsync(available);
            });

            webApi.OnGet($"{pathPrefix}/check-user-ref-token/{{id}}", async(req, res) => {
                string id             = req.PathParams.GetAs("id", (string)null);
                string rawVersionText = req.QueryParams.GetAs("v", "");
                string versionText    = VERSION_CLEAN_REGEX.Replace(rawVersionText, "");
                Version version       = string.IsNullOrEmpty(versionText) ? null : Version.Parse(versionText);
                logger.Debug($"/check-auth-token/{id}?v={version}"); //?join_code={joinCode}");
                if (this.onCheckVersion != null)
                {
                    this.onCheckVersion(version);
                }
                AuthToken authToken = await this.AuthenticateAsync(UserRefTokenAuthenticator.AUTH_TYPE, id);
                await res.WriteAsJsonAsync(authToken);
            });

            webApi.OnPost($"{pathPrefix}/create-anonymous", async(req, res) => {
                Dict data           = await req.ParseAsJsonAsync <Dict>();
                AuthToken authToken = await this.CreateAnonymousUserAsync();
                await res.WriteAsJsonAsync(authToken);
            });

            webApi.OnPost($"{pathPrefix}/register", async(req, res) => {
                Dict registration   = await req.ParseAsJsonAsync <Dict>();
                AuthToken authToken = await this.RegisterAsync(registration);
                await res.WriteAsJsonAsync(authToken);
            });

            webApi.OnPost($"{pathPrefix}/login", async(req, res) => {
                Dict login          = await req.ParseAsJsonAsync <Dict>();
                AuthToken authToken = await this.LoginAsync(login);
                await res.WriteAsJsonAsync(authToken);
            });

            webApi.OnPost($"{pathPrefix}/forgot-password", async(req, res) => {
                Dict data       = await req.ParseAsJsonAsync <Dict>();
                string username = data.GetAs("username", (string)null);
                await this.ForgotPasswordAsync(username);
            });

            webApi.OnPost($"{pathPrefix}/reset-password", async(req, res) => {
                Dict resetPassword  = await req.ParseAsJsonAsync <Dict>();
                AuthToken authToken = await this.ResetPasswordAsync(resetPassword);
                await res.WriteAsJsonAsync(authToken);
            });

            webApi.OnPost($"{pathPrefix}/forgot-username", async(req, res) => {
                Dict data      = await req.ParseAsJsonAsync <Dict>();
                string contact = data.GetAs("contact", (string)null);
                await this.ForgotUsernameAsync(contact);
            });

            webApi.OnPost($"{pathPrefix}/send-email-verify-code", async(req, res) => {
                UserRefToken userRefToken = await this.GetUserRefToken(req);

                string email = await this.database.SelectValueAsync <string>("SELECT email FROM user", vars: userRefToken.userId);
                await this.SendVerifyCodeAsync(email);
            });

            webApi.OnPost($"{pathPrefix}/send-phone-verify-code", async(req, res) => {
                UserRefToken userRefToken = await this.GetUserRefToken(req);

                string phone = await this.database.SelectValueAsync <string>("SELECT phone FROM user", vars: userRefToken.userId);
                await this.SendVerifyCodeAsync(phone);
            });


            webApi.OnPost($"{pathPrefix}/verify", async(req, res) => {
                Dict data = await req.ParseAsJsonAsync <Dict>();
                await this.VerifyAsync(data);
            });
        }