/// <summary> /// Retrieves the unique identifier associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation, /// whose result returns the unique identifier associated with the application. /// </returns> public virtual Task <string> GetIdAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } return(Task.FromResult(application.ApplicationId)); }
public virtual Task <ImmutableArray <string> > GetRolesAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } return(Task.FromResult(application.Roles)); }
/// <summary> /// Retrieves the additional properties associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose /// result returns all the additional properties associated with the application. /// </returns> public virtual Task <JObject> GetPropertiesAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } return(Task.FromResult(application.Properties ?? new JObject())); }
/// <summary> /// Retrieves the physical identifier associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation, /// whose result returns the physical identifier associated with the application. /// </returns> public virtual Task <string> GetPhysicalIdAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } return(Task.FromResult(application.Id.ToString(CultureInfo.InvariantCulture))); }
/// <summary> /// Sets the additional properties associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="properties">The additional properties associated with the application </param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetPropertiesAsync(OpenIdApplication application, JObject properties, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.Properties = properties; return(Task.CompletedTask); }
/// <summary> /// Sets the permissions associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="permissions">The permissions associated with the application </param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetPermissionsAsync(OpenIdApplication application, ImmutableArray <string> permissions, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.Permissions = permissions; return(Task.CompletedTask); }
/// <summary> /// Sets the display name associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="name">The display name associated with the application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetDisplayNameAsync(OpenIdApplication application, string name, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.DisplayName = name; return(Task.CompletedTask); }
/// <summary> /// Sets the consent type associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="type">The consent type associated with the application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetConsentTypeAsync(OpenIdApplication application, string type, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.ConsentType = type; return(Task.CompletedTask); }
/// <summary> /// Sets the client secret associated with an application. /// Note: depending on the manager used to create the application, /// the client secret may be hashed for security reasons. /// </summary> /// <param name="application">The application.</param> /// <param name="secret">The client secret associated with the application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetClientSecretAsync(OpenIdApplication application, string secret, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.ClientSecret = secret; return(Task.CompletedTask); }
/// <summary> /// Sets the callback addresses associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="addresses">The callback addresses associated with the application </param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetRedirectUrisAsync(OpenIdApplication application, ImmutableArray <string> addresses, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.RedirectUris = addresses; return(Task.CompletedTask); }
public virtual Task SetRolesAsync(OpenIdApplication application, ImmutableArray <string> roles, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } application.Roles = roles; _session.Save(application); return(Task.CompletedTask); }
/// <summary> /// Creates a new application. /// </summary> /// <param name="application">The application to create.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task CreateAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } cancellationToken.ThrowIfCancellationRequested(); _session.Save(application); return(_session.CommitAsync()); }
/// <summary> /// Sets the client type associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="type">The client type associated with the application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation. /// </returns> public virtual Task SetClientTypeAsync(OpenIdApplication application, string type, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } if (!Enum.TryParse(type, ignoreCase: true, result: out ClientType value)) { throw new ArgumentException("The specified client type is not valid."); } application.Type = value; return(Task.CompletedTask); }
/// <summary> /// Retrieves the client type associated with an application. /// </summary> /// <param name="application">The application.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <returns> /// A <see cref="Task"/> that can be used to monitor the asynchronous operation, /// whose result returns the client type of the application (by default, "public"). /// </returns> public virtual Task <string> GetClientTypeAsync(OpenIdApplication application, CancellationToken cancellationToken) { if (application == null) { throw new ArgumentNullException(nameof(application)); } // Optimization: avoid double-allocating strings for well-known values. switch (application.Type) { case ClientType.Confidential: return(Task.FromResult(OpenIddictConstants.ClientTypes.Confidential)); case ClientType.Public: return(Task.FromResult(OpenIddictConstants.ClientTypes.Public)); } return(Task.FromResult(application.Type.ToString().ToLowerInvariant())); }
public async Task ExecuteAsync(RecipeExecutionContext context) { if (!string.Equals(context.Name, "OpenIdApplication", StringComparison.OrdinalIgnoreCase)) { return; } var model = context.Step.ToObject <OpenIdApplicationStepModel>(); var application = new OpenIdApplication(); if (model.Id != 0) { application = await _applicationManager.FindByIdAsync(model.Id.ToString(), CancellationToken.None); } application.ClientId = model.ClientId; application.DisplayName = model.DisplayName; application.AllowAuthorizationCodeFlow = model.AllowAuthorizationCodeFlow; application.AllowClientCredentialsFlow = model.AllowClientCredentialsFlow; application.AllowHybridFlow = model.AllowHybridFlow; application.AllowImplicitFlow = model.AllowImplicitFlow; application.AllowPasswordFlow = model.AllowPasswordFlow; application.AllowRefreshTokenFlow = model.AllowRefreshTokenFlow; application.LogoutRedirectUri = model.LogoutRedirectUri; application.RedirectUri = model.RedirectUri; application.SkipConsent = model.SkipConsent; application.RoleNames = model.RoleNames; application.Type = model.Type; if (model.Type == ClientType.Confidential) { await _applicationManager.CreateAsync(application, model.ClientSecret, CancellationToken.None); } else { await _applicationManager.CreateAsync(application, CancellationToken.None); } }
public async Task <IActionResult> Create(CreateOpenIdApplicationViewModel model, string returnUrl = null) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageOpenIdApplications)) { return(Unauthorized()); } if (model.Type == ClientType.Confidential) { var user = await _userManager.FindByNameAsync(User.Identity.Name); await ValidateClientSecretAsync(user, model.ClientSecret, (key, message) => ModelState.AddModelError(key, message)); } else if (model.Type == ClientType.Public && !string.IsNullOrEmpty(model.ClientSecret)) { ModelState.AddModelError(nameof(model.ClientSecret), T["No client secret can be set for public applications."]); } if (!ModelState.IsValid) { var openIdSettings = await _openIdService.GetOpenIdSettingsAsync(); if (!_openIdService.IsValidOpenIdSettings(openIdSettings)) { _notifier.Warning(H["OpenID Connect settings are not properly configured."]); } ViewData["OpenIdSettings"] = openIdSettings; ViewData["ReturnUrl"] = returnUrl; return(View("Create", model)); } var roleNames = new List <string>(); if (model.Type == ClientType.Confidential && model.AllowClientCredentialsFlow) { roleNames = model.RoleEntries.Where(r => r.Selected).Select(r => r.Name).ToList(); } var application = new OpenIdApplication { DisplayName = model.DisplayName, RedirectUri = model.RedirectUri, LogoutRedirectUri = model.LogoutRedirectUri, ClientId = model.ClientId, Type = model.Type, SkipConsent = model.SkipConsent, RoleNames = roleNames, AllowAuthorizationCodeFlow = model.AllowAuthorizationCodeFlow, AllowClientCredentialsFlow = model.AllowClientCredentialsFlow, AllowImplicitFlow = model.AllowImplicitFlow, AllowPasswordFlow = model.AllowPasswordFlow, AllowRefreshTokenFlow = model.AllowRefreshTokenFlow, AllowHybridFlow = model.AllowHybridFlow }; await _applicationManager.CreateAsync(application, model.ClientSecret, HttpContext.RequestAborted); if (string.IsNullOrEmpty(returnUrl)) { return(RedirectToAction("Index")); } return(LocalRedirect(returnUrl)); }
public async Task <IActionResult> Edit(EditOpenIdApplicationViewModel model, string returnUrl = null) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageOpenIdApplications)) { return(Unauthorized()); } if (model.Type == ClientType.Public && !string.IsNullOrEmpty(model.ClientSecret)) { ModelState.AddModelError(nameof(model.ClientSecret), T["No client secret can be set for public applications."]); } else if (model.UpdateClientSecret) { var user = await _userManager.FindByNameAsync(User.Identity.Name); await ValidateClientSecretAsync(user, model.ClientSecret, (key, message) => ModelState.AddModelError(key, message)); } OpenIdApplication application = null; if (ModelState.IsValid) { application = await _applicationManager.FindByIdAsync(model.Id, HttpContext.RequestAborted); if (application == null) { return(NotFound()); } if (application.Type == ClientType.Public && model.Type == ClientType.Confidential && !model.UpdateClientSecret) { ModelState.AddModelError(nameof(model.UpdateClientSecret), T["Setting a new client secret is required"]); } } if (!ModelState.IsValid) { var openIdSettings = await _openIdService.GetOpenIdSettingsAsync(); if (!_openIdService.IsValidOpenIdSettings(openIdSettings)) { _notifier.Warning(H["OpenID Connect settings are not properly configured."]); } ViewData["OpenIdSettings"] = openIdSettings; ViewData["ReturnUrl"] = returnUrl; return(View(model)); } // If the application was confidential and is now public, the client secret must be reset. if (application.Type == ClientType.Confidential && model.Type == ClientType.Public) { model.UpdateClientSecret = true; model.ClientSecret = null; } application.DisplayName = model.DisplayName; application.RedirectUri = model.RedirectUri; application.LogoutRedirectUri = model.LogoutRedirectUri; application.ClientId = model.ClientId; application.Type = model.Type; application.SkipConsent = model.SkipConsent; application.AllowAuthorizationCodeFlow = model.AllowAuthorizationCodeFlow; application.AllowClientCredentialsFlow = model.AllowClientCredentialsFlow; application.AllowImplicitFlow = model.AllowImplicitFlow; application.AllowPasswordFlow = model.AllowPasswordFlow; application.AllowRefreshTokenFlow = model.AllowRefreshTokenFlow; application.AllowHybridFlow = model.AllowHybridFlow; application.RoleNames = new List <string>(); if (application.Type == ClientType.Confidential && application.AllowClientCredentialsFlow) { application.RoleNames = model.RoleEntries.Where(r => r.Selected).Select(r => r.Name).ToList(); } if (model.UpdateClientSecret) { await _applicationManager.UpdateAsync(application, model.ClientSecret, HttpContext.RequestAborted); } else { await _applicationManager.UpdateAsync(application, HttpContext.RequestAborted); } if (string.IsNullOrEmpty(returnUrl)) { return(RedirectToAction("Index")); } return(LocalRedirect(returnUrl)); }
public async Task OpenIdApplicationCanBeUpdated() { // Arrange var recipeName = "app-recipe3"; var clientId = "a1"; var expected = new OpenIdApplicationDescriptor { ClientId = clientId, DisplayName = "Expected Name" }; expected.RedirectUris.UnionWith(new[] { new Uri("https://localhost/redirect") }); var actual = new OpenIdApplicationDescriptor { ClientId = clientId, DisplayName = "Actual Name" }; actual.RedirectUris.UnionWith(new[] { new Uri("https://localhost/x") }); actual.Roles.UnionWith(new[] { "x" }); actual.Permissions.UnionWith(new[] { $"{Permissions.Prefixes.Scope}x" }); var actualDb = new OpenIdApplication { ClientId = actual.ClientId, DisplayName = actual.DisplayName, RedirectUris = actual.RedirectUris.Select(u => u.AbsoluteUri).ToImmutableArray(), Roles = actual.Roles.ToImmutableArray(), Permissions = actual.Permissions.ToImmutableArray() }; var appManagerMock = new Mock <IOpenIdApplicationManager>(MockBehavior.Strict); appManagerMock.Setup(m => m.FindByClientIdAsync( It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns( new ValueTask <object>(actualDb)); appManagerMock.Setup(m => m.PopulateAsync( It.IsAny <OpenIddictApplicationDescriptor>(), It.IsAny <object>(), It.IsAny <CancellationToken>())) .Returns( new ValueTask()); appManagerMock.Setup(m => m.UpdateAsync( It.IsAny <object>(), It.IsAny <OpenIdApplicationDescriptor>(), It.IsAny <CancellationToken>())) .Callback <object, OpenIddictApplicationDescriptor, CancellationToken>((app, desc, c) => actual = (OpenIdApplicationDescriptor)desc) .Returns( new ValueTask()); var step = new OpenIdApplicationStep(appManagerMock.Object); var recipe = JObject.Parse(GetRecipeFileContent(recipeName)); var context = new RecipeExecutionContext { Name = recipe.Property("steps").Value.First.Value <string>("name"), Step = (JObject)recipe.Property("steps").Value.First, }; // Act await step.ExecuteAsync(context); // Assert appManagerMock.Verify(m => m.FindByClientIdAsync( It.Is <string>(ci => ci == expected.ClientId), It.IsAny <CancellationToken>())); appManagerMock.Verify(m => m.UpdateAsync( It.IsAny <object>(), It.IsAny <OpenIdApplicationDescriptor>(), It.IsAny <CancellationToken>())); Assert.Equal(expected.ClientId, actual.ClientId); Assert.Equal(expected.ClientSecret, actual.ClientSecret); Assert.Equal(expected.ConsentType, actual.ConsentType); Assert.Equal(expected.DisplayName, actual.DisplayName); Assert.Equal(expected.Type, actual.Type); Assert.Equal(expected.Permissions, actual.Permissions); Assert.Equal(expected.PostLogoutRedirectUris, actual.PostLogoutRedirectUris); Assert.Equal(expected.RedirectUris, actual.RedirectUris); Assert.Equal(expected.Roles, actual.Roles); }