/* This file is part of the Notesnook Sync Server project (https://notesnook.com/) Copyright (C) 2023 Streetwriters (Private) Limited This program is free software: you can redistribute it and/or modify it under the terms of the Affero GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Affero GNU General Public License for more details. You should have received a copy of the Affero GNU General Public License along with this program. If not, see . */ using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using IdentityModel; using IdentityServer4; using IdentityServer4.Configuration; using IdentityServer4.Models; using IdentityServer4.Services; using IdentityServer4.Stores; using IdentityServer4.Validation; using Microsoft.AspNetCore.Identity; using Streetwriters.Common.Models; using Streetwriters.Identity.Interfaces; namespace Streetwriters.Identity.Helpers { public class TokenGenerationService : ITokenGenerationService { private IPersistedGrantStore PersistedGrantStore { get; set; } private ITokenService TokenService { get; set; } private IUserClaimsPrincipalFactory PrincipalFactory { get; set; } private IdentityServerOptions ISOptions { get; set; } private IdentityServerTools Tools { get; set; } private IResourceStore ResourceStore { get; set; } public TokenGenerationService(ITokenService tokenService, IUserClaimsPrincipalFactory principalFactory, IdentityServerOptions identityServerOptions, IPersistedGrantStore persistedGrantStore, IdentityServerTools tools, IResourceStore resourceStore) { TokenService = tokenService; PrincipalFactory = principalFactory; ISOptions = identityServerOptions; PersistedGrantStore = persistedGrantStore; Tools = tools; ResourceStore = resourceStore; } public async Task CreateAccessTokenAsync(User user, string clientId) { var IdentityPricipal = await PrincipalFactory.CreateAsync(user); var IdentityUser = new IdentityServerUser(user.Id.ToString()); IdentityUser.AdditionalClaims = IdentityPricipal.Claims.ToArray(); IdentityUser.DisplayName = user.UserName; IdentityUser.AuthenticationTime = System.DateTime.UtcNow; IdentityUser.IdentityProvider = IdentityServerConstants.LocalIdentityProvider; var Request = new TokenCreationRequest { Subject = IdentityUser.CreatePrincipal(), IncludeAllIdentityClaims = true, ValidatedRequest = new ValidatedRequest() }; Request.ValidatedRequest.Subject = Request.Subject; Request.ValidatedRequest.SetClient(Config.Clients.FirstOrDefault((c) => c.ClientId == clientId)); Request.ValidatedRequest.AccessTokenType = AccessTokenType.Reference; Request.ValidatedRequest.AccessTokenLifetime = 18000; Request.ValidatedResources = new ResourceValidationResult(new Resources(Config.IdentityResources, Config.ApiResources, Config.ApiScopes)); Request.ValidatedRequest.Options = ISOptions; Request.ValidatedRequest.ClientClaims = IdentityUser.AdditionalClaims; var accessToken = await TokenService.CreateAccessTokenAsync(Request); return await TokenService.CreateSecurityTokenAsync(accessToken); } public async Task TransformTokenRequestAsync(ValidatedTokenRequest request, User user, string grantType, string[] scopes, int lifetime = 20 * 60) { var principal = await PrincipalFactory.CreateAsync(user); var identityUser = new IdentityServerUser(user.Id.ToString()) { DisplayName = user.UserName, AuthenticationTime = System.DateTime.UtcNow, IdentityProvider = IdentityServerConstants.LocalIdentityProvider, AdditionalClaims = principal.Claims.ToArray() }; request.AccessTokenType = AccessTokenType.Jwt; request.AccessTokenLifetime = lifetime; request.GrantType = grantType; request.ValidatedResources = await ResourceStore.CreateResourceValidationResult(new ParsedScopesResult() { ParsedScopes = scopes.Select((scope) => new ParsedScopeValue(scope)).ToArray() }); return identityUser.CreatePrincipal(); } public async Task CreateAccessTokenFromValidatedRequestAsync(ValidatedTokenRequest validatedRequest, User user, string[] scopes, int lifetime = 20 * 60) { var request = new TokenCreationRequest { Subject = await this.TransformTokenRequestAsync(validatedRequest, user, validatedRequest.GrantType, scopes, lifetime), IncludeAllIdentityClaims = true, ValidatedRequest = validatedRequest, ValidatedResources = validatedRequest.ValidatedResources }; var accessToken = await TokenService.CreateAccessTokenAsync(request); return await TokenService.CreateSecurityTokenAsync(accessToken); } } }