/// <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()));
        }
Пример #15
0
        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);
            }
        }
Пример #16
0
        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));
        }
Пример #17
0
        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));
        }
Пример #18
0
        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);
        }