public async Task <IActionResult> VerifyToken() { string token = this.GetTokenFromHeader(out string tokenTypeStr); if (string.IsNullOrEmpty(token)) { return(this.AuthorizationHeaderMissing()); } if (!TokenTypeExtensions.TryParseTokenType(tokenTypeStr, out var tokenType)) { throw ErtisAuthException.UnsupportedTokenType(); } var validationResult = await this.tokenService.VerifyTokenAsync(token, tokenType); if (validationResult.IsValidated) { return(this.Ok(validationResult)); } else { return(this.Unauthorized(validationResult)); } }
public async Task <IActionResult> WhoAmI() { string token = this.GetTokenFromHeader(out string tokenTypeStr); if (string.IsNullOrEmpty(token)) { return(this.AuthorizationHeaderMissing()); } if (!TokenTypeExtensions.TryParseTokenType(tokenTypeStr, out var tokenType)) { throw ErtisAuthException.UnsupportedTokenType(); } var user = await this.tokenService.WhoAmIAsync(token, tokenType); if (user != null) { return(this.Ok(user)); } else { return(this.InvalidToken()); } }
// ReSharper disable once OutParameterValueIsAlwaysDiscarded.Local private bool IsDeletable(string id, string membershipId, out IEnumerable <string> errors) { var userType = this.GetAsync(membershipId, id).ConfigureAwait(false).GetAwaiter().GetResult(); if (userType == null) { throw ErtisAuthException.UserTypeNotFound(id, "_id"); } var query = QueryBuilder.Where(QueryBuilder.Equals("membership_id", membershipId), QueryBuilder.Equals("base_type", userType.Name)); var inheritedUserTypes = this.QueryAsync(query.ToString()).ConfigureAwait(false).GetAwaiter().GetResult(); if (inheritedUserTypes.Items.Any()) { errors = new[] { $"This user type is currently using as the base type of some other user types. ({string.Join(", ", inheritedUserTypes.Items.Select(x => x["title"]))})" }; return(false); } errors = null; return(true); }
protected override void Overwrite(Application destination, Application source) { destination.Id = source.Id; destination.MembershipId = source.MembershipId; destination.Sys = source.Sys; if (this.IsIdentical(destination, source)) { throw ErtisAuthException.IdenticalDocument(); } if (string.IsNullOrEmpty(destination.Name)) { destination.Name = source.Name; } if (string.IsNullOrEmpty(destination.Role)) { destination.Role = source.Role; } if (destination.Permissions == null) { destination.Permissions = source.Permissions; } if (destination.Forbidden == null) { destination.Forbidden = source.Forbidden; } }
public virtual async Task <TModel> UpdateAsync(TModel model) { // Overwrite var current = await this.GetAsync(model.Id); if (current == null) { throw this.GetNotFoundError(model.Id); } this.Overwrite(model, current); // Model validation if (!this.ValidateModel(model, out var errors)) { throw ErtisAuthException.ValidationError(errors); } // Check existing if (await this.IsAlreadyExistAsync(model, current)) { throw this.GetAlreadyExistError(model); } var dto = Mapper.Current.Map <TModel, TDto>(model); var updated = await this.repository.UpdateAsync(dto); return(Mapper.Current.Map <TDto, TModel>(updated)); }
public virtual TModel Update(TModel model) { // Overwrite var current = this.Get(model.Id); if (current == null) { throw this.GetNotFoundError(model.Id); } this.Overwrite(model, current); // Model validation if (!this.ValidateModel(model, out var errors)) { throw ErtisAuthException.ValidationError(errors); } // Check existing if (this.IsAlreadyExist(model, current)) { throw this.GetAlreadyExistError(model); } var dto = Mapper.Current.Map <TModel, TDto>(model); var updatedDto = this.repository.Update(dto); var updated = Mapper.Current.Map <TDto, TModel>(updatedDto); this.OnUpdated?.Invoke(this, new UpdateResourceEventArgs <TModel>(current, updated)); return(updated); }
public virtual TModel Create(Utilizer utilizer, string membershipId, TModel model) { // Check membership var membership = this.membershipService.Get(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } else { model.MembershipId = membershipId; } // Model validation if (!this.ValidateModel(model, out var errors)) { throw ErtisAuthException.ValidationError(errors); } // Check existing if (this.IsAlreadyExist(model, membershipId)) { throw this.GetAlreadyExistError(model); } // Insert to database var dto = Mapper.Current.Map <TModel, TDto>(model); var insertedDto = this.repository.Insert(dto); var inserted = Mapper.Current.Map <TDto, TModel>(insertedDto); this.OnCreated?.Invoke(this, new CreateResourceEventArgs <TModel>(utilizer, inserted)); return(inserted); }
public static string ExtractToken(string authorizationHeader, out string tokenType) { if (string.IsNullOrEmpty(authorizationHeader)) { tokenType = null; return(null); } var parts = authorizationHeader.Split(' '); if (parts.Length > 2) { throw ErtisAuthException.InvalidToken(); } if (parts.Length == 2) { var supportedTokenTypes = Enum.GetValues(typeof(SupportedTokenTypes)).Cast <SupportedTokenTypes>().Select(x => x.ToString()); if (!supportedTokenTypes.Contains(parts[0])) { throw ErtisAuthException.UnsupportedTokenType(); } tokenType = parts[0]; return(parts[1]); } tokenType = null; return(parts[0]); }
public async Task <dynamic> MigrateAsync(string connectionString, Membership _membership, UserWithPassword _user) { // Validation var databaseInformation = Ertis.MongoDB.Helpers.ConnectionStringHelper.ParseConnectionString(connectionString); var connectionString1 = Ertis.MongoDB.Helpers.ConnectionStringHelper.GenerateConnectionString(this.databaseSettings); var connectionString2 = Ertis.MongoDB.Helpers.ConnectionStringHelper.GenerateConnectionString(databaseInformation); if (connectionString1 != connectionString2) { throw ErtisAuthException.MigrationRejected("Connection string could not validated"); } // 1. Membership var membership = await this.membershipService.CreateAsync(new Membership { Name = _membership.Name, DefaultEncoding = _membership.DefaultEncoding, HashAlgorithm = _membership.HashAlgorithm, ExpiresIn = _membership.ExpiresIn, RefreshTokenExpiresIn = _membership.RefreshTokenExpiresIn, SecretKey = string.IsNullOrEmpty(_membership.SecretKey) ? GenerateRandomSecretKey(32) : _membership.SecretKey }); // Utilizer var utilizer = new Utilizer { Role = Rbac.ReservedRoles.Administrator, Type = Utilizer.UtilizerType.System, MembershipId = membership.Id }; // 2. Role var adminRole = await this.roleService.CreateAsync(utilizer, membership.Id, new Role { Name = Rbac.ReservedRoles.Administrator, Description = "Administrator", MembershipId = membership.Id, Permissions = RoleHelper.AssertAdminPermissionsForReservedResources() }); // 3. User (admin) var adminUser = await this.userService.CreateAsync(utilizer, membership.Id, new UserWithPassword { Username = _user.Username, FirstName = _user.FirstName, LastName = _user.LastName, EmailAddress = _user.EmailAddress, Role = adminRole.Name, MembershipId = membership.Id, PasswordHash = this.cryptographyService.CalculatePasswordHash(membership, _user.PasswordHash) }); return(new { membership, user = adminUser, role = adminRole }); }
public async Task <IActionResult> Migrate([FromBody] MigrationModel model) { if (model.Membership == null) { throw ErtisAuthException.ValidationError(new[] { "membership is required" }); } if (model.User == null) { throw ErtisAuthException.ValidationError(new[] { "user is required" }); } if (!this.Request.Headers.ContainsKey("ConnectionString")) { throw ErtisAuthException.ValidationError(new[] { "ConnectionString must be post in header" }); } var connectionString = this.Request.Headers["ConnectionString"]; var membership = new Membership { Name = model.Membership.Name, ExpiresIn = model.Membership.ExpiresIn, RefreshTokenExpiresIn = model.Membership.RefreshTokenExpiresIn, HashAlgorithm = model.Membership.HashAlgorithm, DefaultEncoding = model.Membership.DefaultEncoding, SecretKey = model.Membership.SecretKey, }; var user = new UserWithPasswordHash { Username = model.User.Username, EmailAddress = model.User.EmailAddress, FirstName = model.User.FirstName, LastName = model.User.LastName, PasswordHash = model.User.Password, Role = model.User.Role, Forbidden = model.User.Forbidden, Permissions = model.User.Permissions }; Application application = null; if (model.Application != null) { application = new Application { Name = model.Application.Name, Role = model.Application.Role }; } this.Request.HttpContext.Items.Add("SysUtilizer", "migration"); var migrationResult = await this.migrationService.MigrateAsync(connectionString, membership, user, application); return(this.Ok(migrationResult)); }
public override bool Delete(Utilizer utilizer, string membershipId, string id) { // Is Deletable? if (!this.IsDeletable(id, membershipId, out var _)) { throw ErtisAuthException.UserTypeCanNotBeDelete(); } return(base.Delete(utilizer, membershipId, id)); }
public override async ValueTask <bool> DeleteAsync(Utilizer utilizer, string membershipId, string id) { // Is Deletable? if (!this.IsDeletable(id, membershipId, out var _)) { throw ErtisAuthException.UserTypeCanNotBeDelete(); } return(await base.DeleteAsync(utilizer, membershipId, id)); }
public override async ValueTask <bool> DeleteAsync(string id) { var membershipBoundedResources = await this.GetMembershipBoundedResourcesAsync(id); if (membershipBoundedResources.Any()) { throw ErtisAuthException.MembershipCouldNotDeleted(id); } return(await base.DeleteAsync(id)); }
private async Task <Membership> CheckMembershipAsync(string membershipId) { var membership = await this._membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } return(membership); }
public IPaginationCollection <dynamic> GetDynamic(string membershipId, int?skip, int?limit, bool withCount, string orderBy, SortDirection?sortDirection) { var membership = this.membershipService.Get(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } return(this.repository.Query(x => x.MembershipId == membershipId, skip, limit, withCount, orderBy, sortDirection)); }
public async Task <IPaginationCollection <dynamic> > GetDynamicAsync(string membershipId, int?skip, int?limit, bool withCount, string orderBy, SortDirection?sortDirection) { var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } return(await this.eventRepository.QueryAsync(x => x.MembershipId == membershipId, skip, limit, withCount, orderBy, sortDirection)); }
public override bool Delete(string id) { var membershipBoundedResources = this.GetMembershipBoundedResources(id); if (membershipBoundedResources.Any()) { throw ErtisAuthException.MembershipCouldNotDeleted(id); } return(base.Delete(id)); }
protected override void Overwrite(UserType destination, UserType source) { destination.Id = source.Id; destination.MembershipId = source.MembershipId; destination.Sys = source.Sys; if (this.IsIdentical(destination, source)) { throw ErtisAuthException.IdenticalDocument(); } }
public virtual async Task <TModel> GetAsync(string membershipId, string id) { var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } var dto = await this.repository.FindOneAsync(x => x.Id == id && x.MembershipId == membershipId); return(Mapper.Current.Map <TDto, TModel>(dto)); }
public override ErtisAuthEventBase Get(string membershipId, string id) { var membership = this.membershipService.Get(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } var dto = this.repository.FindOne(x => x.Id == id && x.MembershipId == membershipId); return(DtoToModel(dto)); }
public override async ValueTask <ErtisAuthEventBase> GetAsync(string membershipId, string id) { var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } var dto = await this.repository.FindOneAsync(x => x.Id == id && x.MembershipId == membershipId); return(DtoToModel(dto)); }
private async Task <UserType> GetUserTypeAsync(DynamicObject model, string membershipId, bool fallbackWithOriginUserType = false) { if (model.TryGetValue("user_type", out string userTypeName, out _) && !string.IsNullOrEmpty(userTypeName)) { var userType = await this._userTypeService.GetByNameOrSlugAsync(membershipId, userTypeName); if (userType == null) { throw ErtisAuthException.UserTypeNotFound(userTypeName, "name"); } return(userType); }
protected override void Overwrite(MailHook destination, MailHook source) { destination.Id = source.Id; destination.MembershipId = source.MembershipId; destination.Sys = source.Sys; if (this.IsIdentical(destination, source)) { throw ErtisAuthException.IdenticalDocument(); } if (string.IsNullOrEmpty(destination.Name)) { destination.Name = source.Name; } if (string.IsNullOrEmpty(destination.Description)) { destination.Description = source.Description; } if (string.IsNullOrEmpty(destination.Event)) { destination.Event = source.Event; } if (string.IsNullOrEmpty(destination.Status)) { destination.Status = source.Status; } if (string.IsNullOrEmpty(destination.MailSubject)) { destination.MailSubject = source.MailSubject; } if (string.IsNullOrEmpty(destination.MailTemplate)) { destination.MailTemplate = source.MailTemplate; } if (string.IsNullOrEmpty(destination.FromName)) { destination.FromName = source.FromName; } if (string.IsNullOrEmpty(destination.FromAddress)) { destination.FromAddress = source.FromAddress; } }
public async Task <ITokenValidationResult> VerifyTokenAsync(string token, SupportedTokenTypes tokenType, bool fireEvent = true) { switch (tokenType) { case SupportedTokenTypes.Bearer: return(await this.VerifyBearerTokenAsync(token, fireEvent)); case SupportedTokenTypes.Basic: return(await this.VerifyBasicTokenAsync(token, fireEvent)); default: throw ErtisAuthException.UnsupportedTokenType(); } }
public virtual async ValueTask <TModel> UpdateAsync(Utilizer utilizer, string membershipId, TModel model) { // Check membership var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } else { model.MembershipId = membershipId; } // Overwrite var current = await this.GetAsync(membershipId, model.Id); if (current == null) { throw this.GetNotFoundError(model.Id); } this.Overwrite(model, current); // Touch model model = await this.TouchAsync(model, CrudOperation.Update); // Model validation if (!this.ValidateModel(model, out var errors)) { throw ErtisAuthException.ValidationError(errors); } // Check existing if (await this.IsAlreadyExistAsync(model, membershipId, current)) { throw this.GetAlreadyExistError(model); } model.MembershipId = membershipId; var dto = Mapper.Current.Map <TModel, TDto>(model); var updatedDto = await this.repository.UpdateAsync(dto); var updated = Mapper.Current.Map <TDto, TModel>(updatedDto); this.OnUpdated?.Invoke(this, new UpdateResourceEventArgs <TModel>(utilizer, current, updated)); return(updated); }
private static void CheckReservedUserTypeName(string name) { var reservedNames = new[] { OriginUserType.Name, }; foreach (var reservedName in reservedNames) { if (name == reservedName) { throw ErtisAuthException.ReservedUserTypeName(reservedName); } } }
protected async ValueTask <TModel> GetAsync(string membershipId, Expression <Func <TDto, bool> > expression) { var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } var entities = await this.repository.FindAsync(expression); var entity = entities.Items.FirstOrDefault(x => x.MembershipId == membershipId); return(Mapper.Current.Map <TDto, TModel>(entity)); }
public async Task SetPasswordAsync(Utilizer utilizer, string membershipId, string resetToken, string usernameOrEmailAddress, string password) { if (string.IsNullOrEmpty(usernameOrEmailAddress)) { throw ErtisAuthException.ValidationError(new [] { "Username or email required!" }); } var membership = await this.membershipService.GetAsync(membershipId); if (membership == null) { throw ErtisAuthException.MembershipNotFound(membershipId); } var user = await this.GetUserWithPasswordAsync(usernameOrEmailAddress, usernameOrEmailAddress, membershipId); if (user == null) { throw ErtisAuthException.UserNotFound(usernameOrEmailAddress, "username or email_address"); } if (utilizer.Role == Rbac.ReservedRoles.Administrator || utilizer.Id == user.Id) { if (this.jwtService.TryDecodeToken(resetToken, out var securityToken)) { var expireTime = securityToken.ValidTo.ToLocalTime(); if (DateTime.Now > expireTime) { // Token was expired! throw ErtisAuthException.TokenWasExpired(); } await this.ChangePasswordAsync(utilizer, membershipId, user.Id, password); } else { // Reset token could not decoded! throw ErtisAuthException.InvalidToken(); } } else { throw ErtisAuthException.AccessDenied("Unauthorized access"); } }
public async Task <IActionResult> WhoAmI() { string token = this.GetTokenFromHeader(out string tokenTypeStr); if (string.IsNullOrEmpty(token)) { return(this.AuthorizationHeaderMissing()); } if (!TokenTypeExtensions.TryParseTokenType(tokenTypeStr, out var tokenType)) { throw ErtisAuthException.UnsupportedTokenType(); } switch (tokenType) { case SupportedTokenTypes.None: throw ErtisAuthException.UnsupportedTokenType(); case SupportedTokenTypes.Basic: var application = await this.tokenService.WhoAmIAsync(new BasicToken(token)); if (application != null) { return(this.Ok(application)); } else { return(this.InvalidToken()); } case SupportedTokenTypes.Bearer: var user = await this.tokenService.WhoAmIAsync(BearerToken.CreateTemp(token)); if (user != null) { return(this.Ok(user)); } else { return(this.InvalidToken()); } default: throw ErtisAuthException.UnsupportedTokenType(); } }
private void VerifyRolePermissions(Role role, string subjectId, HttpContext httpContext) { var endpoint = httpContext.GetEndpoint(); // Subject var rbacSubjectSegment = new RbacSegment(subjectId); // Resource var rbacResourceSegment = RbacSegment.All; var resourceMetadata = endpoint?.Metadata?.FirstOrDefault(x => x.GetType() == typeof(RbacResourceAttribute)); if (resourceMetadata is RbacResourceAttribute rbacResourceAttribute) { rbacResourceSegment = rbacResourceAttribute.ResourceSegment; } // Action var rbacActionSegment = RbacSegment.All; var actionMetadata = endpoint?.Metadata?.FirstOrDefault(x => x.GetType() == typeof(RbacActionAttribute)); if (actionMetadata is RbacActionAttribute rbacActionAttribute) { rbacActionSegment = rbacActionAttribute.ActionSegment; } // Object var rbacObjectSegment = RbacSegment.All; var objectMetadata = endpoint?.Metadata?.FirstOrDefault(x => x.GetType() == typeof(RbacObjectAttribute)); var routeData = httpContext.GetRouteData(); if (routeData?.Values != null && objectMetadata is RbacObjectAttribute rbacObjectAttribute) { if (routeData.Values.ContainsKey(rbacObjectAttribute.RouteParameterName)) { var rbacObject = routeData.Values[rbacObjectAttribute.RouteParameterName]; rbacObjectSegment = new RbacSegment(rbacObject.ToString()); } } var rbac = new Rbac(rbacSubjectSegment, rbacResourceSegment, rbacActionSegment, rbacObjectSegment); if (!role.HasPermission(rbac)) { throw ErtisAuthException.AccessDenied("Your authorization role is unauthorized for this action"); } }