public virtual async Task SendPhoneRegisterCodeAsync(SendPhoneRegisterCodeDto input) { await CheckSelfRegistrationAsync(); await CheckNewUserPhoneNumberNotBeUsedAsync(input.PhoneNumber); var securityTokenCacheKey = SmsSecurityTokenCacheItem.CalculateCacheKey(input.PhoneNumber, "SmsVerifyCode"); var securityTokenCacheItem = await SecurityTokenCache.GetAsync(securityTokenCacheKey); var interval = await SettingProvider.GetAsync(IdentitySettingNames.User.SmsRepetInterval, 1); if (securityTokenCacheItem != null) { throw new UserFriendlyException(L["SendRepeatSmsVerifyCode", interval]); } var template = await SettingProvider.GetOrNullAsync(IdentitySettingNames.User.SmsNewUserRegister); // 安全令牌 var securityToken = GuidGenerator.Create().ToString("N"); var code = TotpService.GenerateCode(Encoding.Unicode.GetBytes(securityToken), securityTokenCacheKey); securityTokenCacheItem = new SmsSecurityTokenCacheItem(code.ToString(), securityToken); await SecurityCodeSender.SendPhoneConfirmedCodeAsync( input.PhoneNumber, securityTokenCacheItem.Token, template); await SecurityTokenCache .SetAsync(securityTokenCacheKey, securityTokenCacheItem, new DistributedCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(interval) }); }
public async Task <IActionResult> Send(TotpRequest request) { var userId = User.FindSubjectId(); if (string.IsNullOrEmpty(userId)) { return(Forbid()); } switch (request.Channel) { case TotpDeliveryChannel.Sms: var result = await TotpService.Send(options => options.UsePrincipal(User).WithMessage(request.Message).UsingSms().WithPurpose(request.Purpose)); if (!result.Success) { ModelState.AddModelError(nameof(request.Channel), result.Errors.FirstOrDefault() ?? "An error occured."); return(BadRequest(new ValidationProblemDetails(ModelState))); } break; case TotpDeliveryChannel.Email: case TotpDeliveryChannel.Telephone: case TotpDeliveryChannel.Viber: default: return(StatusCode(405)); } return(NoContent()); }
public virtual async Task RegisterAsync(PhoneRegisterDto input) { await CheckSelfRegistrationAsync(); await IdentityOptions.SetAsync(); await CheckNewUserPhoneNumberNotBeUsedAsync(input.PhoneNumber); var securityTokenCacheKey = SmsSecurityTokenCacheItem.CalculateCacheKey(input.PhoneNumber, "SmsVerifyCode"); var securityTokenCacheItem = await SecurityTokenCache.GetAsync(securityTokenCacheKey); if (securityTokenCacheItem == null) { // 验证码过期 throw new UserFriendlyException(L["InvalidSmsVerifyCode"]); } // 验证码是否有效 if (input.Code.Equals(securityTokenCacheItem.Token) && int.TryParse(input.Code, out int token)) { var securityToken = Encoding.Unicode.GetBytes(securityTokenCacheItem.SecurityToken); // 校验totp验证码 if (TotpService.ValidateCode(securityToken, token, securityTokenCacheKey)) { var userEmail = input.EmailAddress ?? $"{input.PhoneNumber}@{CurrentTenant.Name ?? "default"}.io";//如果邮件地址不验证,随意写入一个 var userName = input.UserName ?? input.PhoneNumber; var user = new IdentityUser(GuidGenerator.Create(), userName, userEmail, CurrentTenant.Id) { Name = input.Name ?? input.PhoneNumber }; await UserStore.SetPhoneNumberAsync(user, input.PhoneNumber); await UserStore.SetPhoneNumberConfirmedAsync(user, true); (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); (await UserManager.AddDefaultRolesAsync(user)).CheckErrors(); await SecurityTokenCache.RemoveAsync(securityTokenCacheKey); await CurrentUnitOfWork.SaveChangesAsync(); return; } } // 验证码无效 throw new UserFriendlyException(L["InvalidSmsVerifyCode"]); }
public async Task <IActionResult> Verify(TotpVerificationRequest request) { var userId = User.FindSubjectId(); if (string.IsNullOrEmpty(userId)) { return(Forbid()); } var result = await TotpService.Verify(User, request.Code, request.Provider, request.Purpose); if (!result.Success) { ModelState.AddModelError(nameof(request.Code), Localizer["Invalid code"]); return(BadRequest(new ValidationProblemDetails(ModelState))); } return(NoContent()); }
public static void Init(string customUserAgent = null) { if (Inited) { return; } Inited = true; var platformUtilsService = Resolve <IPlatformUtilsService>("platformUtilsService"); var storageService = Resolve <IStorageService>("storageService"); var secureStorageService = Resolve <IStorageService>("secureStorageService"); var cryptoPrimitiveService = Resolve <ICryptoPrimitiveService>("cryptoPrimitiveService"); var i18nService = Resolve <II18nService>("i18nService"); var messagingService = Resolve <IMessagingService>("messagingService"); SearchService searchService = null; var stateService = new StateService(); var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService); var cryptoService = new CryptoService(storageService, secureStorageService, cryptoFunctionService); var tokenService = new TokenService(storageService); var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) => { messagingService.Send("logout", expired); return(Task.FromResult(0)); }, customUserAgent); var appIdService = new AppIdService(storageService); var userService = new UserService(storageService, tokenService); var settingsService = new SettingsService(userService, storageService); var cipherService = new CipherService(cryptoService, userService, settingsService, apiService, storageService, i18nService, () => searchService); var folderService = new FolderService(cryptoService, userService, apiService, storageService, i18nService, cipherService); var collectionService = new CollectionService(cryptoService, userService, storageService, i18nService); searchService = new SearchService(cipherService); var lockService = new LockService(cryptoService, userService, platformUtilsService, storageService, folderService, cipherService, collectionService, searchService, messagingService, null); var policyService = new PolicyService(storageService, userService); var syncService = new SyncService(userService, apiService, settingsService, folderService, cipherService, cryptoService, collectionService, storageService, messagingService, policyService, (bool expired) => { messagingService.Send("logout", expired); return(Task.FromResult(0)); }); var passwordGenerationService = new PasswordGenerationService(cryptoService, storageService, cryptoFunctionService); var totpService = new TotpService(storageService, cryptoFunctionService); var authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService, i18nService, platformUtilsService, messagingService, lockService); var exportService = new ExportService(folderService, cipherService); var auditService = new AuditService(cryptoFunctionService, apiService); var environmentService = new EnvironmentService(apiService, storageService); var eventService = new EventService(storageService, apiService, userService, cipherService); Register <IStateService>("stateService", stateService); Register <ICryptoFunctionService>("cryptoFunctionService", cryptoFunctionService); Register <ICryptoService>("cryptoService", cryptoService); Register <ITokenService>("tokenService", tokenService); Register <IApiService>("apiService", apiService); Register <IAppIdService>("appIdService", appIdService); Register <IUserService>("userService", userService); Register <ISettingsService>("settingsService", settingsService); Register <ICipherService>("cipherService", cipherService); Register <IFolderService>("folderService", folderService); Register <ICollectionService>("collectionService", collectionService); Register <ISearchService>("searchService", searchService); Register <IPolicyService>("policyService", policyService); Register <ISyncService>("syncService", syncService); Register <ILockService>("lockService", lockService); Register <IPasswordGenerationService>("passwordGenerationService", passwordGenerationService); Register <ITotpService>("totpService", totpService); Register <IAuthService>("authService", authService); Register <IExportService>("exportService", exportService); Register <IAuditService>("auditService", auditService); Register <IEnvironmentService>("environmentService", environmentService); Register <IEventService>("eventService", eventService); }
public static void Init(string customUserAgent = null, string clearCipherCacheKey = null, string[] allClearCipherCacheKeys = null) { if (Inited) { return; } Inited = true; var platformUtilsService = Resolve <IPlatformUtilsService>("platformUtilsService"); var storageService = Resolve <IStorageService>("storageService"); var stateService = Resolve <IStateService>("stateService"); var i18nService = Resolve <II18nService>("i18nService"); var messagingService = Resolve <IMessagingService>("messagingService"); var cryptoFunctionService = Resolve <ICryptoFunctionService>("cryptoFunctionService"); var cryptoService = Resolve <ICryptoService>("cryptoService"); SearchService searchService = null; var tokenService = new TokenService(stateService); var apiService = new ApiService(tokenService, platformUtilsService, (extras) => { messagingService.Send("logout", extras); return(Task.CompletedTask); }, customUserAgent); var appIdService = new AppIdService(storageService); var organizationService = new OrganizationService(stateService); var settingsService = new SettingsService(stateService); var fileUploadService = new FileUploadService(apiService); var cipherService = new CipherService(cryptoService, stateService, settingsService, apiService, fileUploadService, storageService, i18nService, () => searchService, clearCipherCacheKey, allClearCipherCacheKeys); var folderService = new FolderService(cryptoService, stateService, apiService, i18nService, cipherService); var collectionService = new CollectionService(cryptoService, stateService, i18nService); var sendService = new SendService(cryptoService, stateService, apiService, fileUploadService, i18nService, cryptoFunctionService); searchService = new SearchService(cipherService, sendService); var policyService = new PolicyService(stateService, organizationService); var keyConnectorService = new KeyConnectorService(stateService, cryptoService, tokenService, apiService, organizationService); var vaultTimeoutService = new VaultTimeoutService(cryptoService, stateService, platformUtilsService, folderService, cipherService, collectionService, searchService, messagingService, tokenService, policyService, keyConnectorService, (extras) => { messagingService.Send("locked", extras); return(Task.CompletedTask); }, (extras) => { messagingService.Send("logout", extras); return(Task.CompletedTask); }); var syncService = new SyncService(stateService, apiService, settingsService, folderService, cipherService, cryptoService, collectionService, organizationService, messagingService, policyService, sendService, keyConnectorService, (extras) => { messagingService.Send("logout", extras); return(Task.CompletedTask); }); var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService, cryptoFunctionService, policyService); var totpService = new TotpService(cryptoFunctionService); var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService, tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService, keyConnectorService); var exportService = new ExportService(folderService, cipherService, cryptoService); var auditService = new AuditService(cryptoFunctionService, apiService); var environmentService = new EnvironmentService(apiService, stateService); var eventService = new EventService(apiService, stateService, organizationService, cipherService); var userVerificationService = new UserVerificationService(apiService, platformUtilsService, i18nService, cryptoService); Register <ITokenService>("tokenService", tokenService); Register <IApiService>("apiService", apiService); Register <IAppIdService>("appIdService", appIdService); Register <IOrganizationService>("organizationService", organizationService); Register <ISettingsService>("settingsService", settingsService); Register <ICipherService>("cipherService", cipherService); Register <IFolderService>("folderService", folderService); Register <ICollectionService>("collectionService", collectionService); Register <ISendService>("sendService", sendService); Register <ISearchService>("searchService", searchService); Register <IPolicyService>("policyService", policyService); Register <ISyncService>("syncService", syncService); Register <IVaultTimeoutService>("vaultTimeoutService", vaultTimeoutService); Register <IPasswordGenerationService>("passwordGenerationService", passwordGenerationService); Register <ITotpService>("totpService", totpService); Register <IAuthService>("authService", authService); Register <IExportService>("exportService", exportService); Register <IAuditService>("auditService", auditService); Register <IEnvironmentService>("environmentService", environmentService); Register <IEventService>("eventService", eventService); Register <IKeyConnectorService>("keyConnectorService", keyConnectorService); Register <IUserVerificationService>("userVerificationService", userVerificationService); }
public async Task <IEndpointResult> ProcessAsync(HttpContext httpContext) { Logger.LogInformation($"[{nameof(InitRegistrationEndpoint)}] Started processing trusted device registration initiation endpoint."); var isPostRequest = HttpMethods.IsPost(httpContext.Request.Method); var isApplicationFormContentType = httpContext.Request.HasApplicationFormContentType(); // Validate HTTP request type and method. if (!isPostRequest || !isApplicationFormContentType) { return(Error(OidcConstants.TokenErrors.InvalidRequest, "Request must be of type 'POST' and have a Content-Type equal to 'application/x-www-form-urlencoded'.")); } // Ensure that a valid 'Authorization' header exists. var tokenUsageResult = await Token.Validate(httpContext); if (!tokenUsageResult.TokenFound) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, "No access token is present in the request.")); } // Validate request data and access token. var parameters = (await httpContext.Request.ReadFormAsync()).AsNameValueCollection(); var requestValidationResult = await Request.Validate(parameters, tokenUsageResult.Token); if (requestValidationResult.IsError) { return(Error(requestValidationResult.Error, requestValidationResult.ErrorDescription)); } // Ensure device is not already registered or belongs to any other user. var existingDevice = await UserDeviceStore.GetByDeviceId(requestValidationResult.DeviceId); var isNewDeviceOrOwnedByUser = existingDevice == null || existingDevice.UserId.Equals(requestValidationResult.UserId, StringComparison.OrdinalIgnoreCase); if (!isNewDeviceOrOwnedByUser) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, "Device does not belong to the this user.")); } // Ensure that the principal has declared a phone number which is also confirmed. // We will get these 2 claims by retrieving the identity resources from the store (using the requested scopes existing in the access token) and then calling the profile service. // This will help us make sure that the 'phone' scope was requested and finally allowed in the token endpoint. var identityResources = await ResourceStore.FindEnabledIdentityResourcesByScopeAsync(requestValidationResult.RequestedScopes); var resources = new Resources(identityResources, Enumerable.Empty <ApiResource>(), Enumerable.Empty <ApiScope>()); var validatedResources = new ResourceValidationResult(resources); if (!validatedResources.Succeeded) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, "Identity resources could be validated.")); } var requestedClaimTypes = resources.IdentityResources.SelectMany(x => x.UserClaims).Distinct(); var profileDataRequestContext = new ProfileDataRequestContext(requestValidationResult.Principal, requestValidationResult.Client, IdentityServerConstants.ProfileDataCallers.UserInfoEndpoint, requestedClaimTypes) { RequestedResources = validatedResources }; await ProfileService.GetProfileDataAsync(profileDataRequestContext); var profileClaims = profileDataRequestContext.IssuedClaims; var phoneNumberClaim = profileClaims.FirstOrDefault(x => x.Type == JwtClaimTypes.PhoneNumber); var phoneNumberVerifiedClaim = profileClaims.FirstOrDefault(x => x.Type == JwtClaimTypes.PhoneNumberVerified); if (string.IsNullOrWhiteSpace(phoneNumberClaim?.Value) || phoneNumberVerifiedClaim == null || (bool.TryParse(phoneNumberVerifiedClaim.Value, out var phoneNumberVerified) && !phoneNumberVerified)) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, "User does not have a phone number or the phone number is not verified.")); } var otpAuthenticatedValue = profileClaims.FirstOrDefault(x => x.Type == BasicClaimTypes.OtpAuthenticated)?.Value; var otpAuthenticated = !string.IsNullOrWhiteSpace(otpAuthenticatedValue) && bool.Parse(otpAuthenticatedValue); if (!otpAuthenticated) { // Send OTP code. void messageBuilder(TotpMessageBuilder message) { var builder = message.UsePrincipal(requestValidationResult.Principal).WithMessage(IdentityMessageDescriber.DeviceRegistrationCodeMessage(existingDevice?.Name, requestValidationResult.InteractionMode)); if (requestValidationResult.DeliveryChannel == TotpDeliveryChannel.Sms) { builder.UsingSms(); } else { builder.UsingViber(); } builder.WithPurpose(Constants.TrustedDeviceOtpPurpose(requestValidationResult.UserId, requestValidationResult.DeviceId)); } var totpResult = await TotpService.Send(messageBuilder); if (!totpResult.Success) { return(Error(totpResult.Error)); } } // Create endpoint response. var response = await Response.Generate(requestValidationResult); Logger.LogInformation($"[{nameof(InitRegistrationEndpoint)}] Trusted device registration initiation endpoint success."); return(new InitRegistrationResult(response)); }