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)
            });
        }
示例#2
0
        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());
        }
示例#3
0
        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"]);
        }
示例#4
0
        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());
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        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));
        }