private static void ConfigureIdentityCreationAndCustomHandlers(IAppBuilder app, OpenIdConnectAuthenticationOptions identityOptions, bool autoLinkExternalAccount = false) { // Configure AutoLinking, which allows Umbraco to automatically add a first-time // visitor to its database without prompting the user. identityOptions.SetExternalSignInAutoLinkOptions ( new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: autoLinkExternalAccount, defaultUserGroups: null, defaultCulture: null) ); // Here we customize two event handlers, one for transforming the claims recevied and another for // making sure the IdP Url is set (as the authority uri) in the OpenIdConnect request so it becomes // easily accessible to the rest of the processing pipeline. The ReadySignOn mobile app uses the // IdP Url to search for maching record(s) in its secure vault upong receving an authentication request. identityOptions.Notifications = new OpenIdConnectAuthenticationNotifications { SecurityTokenValidated = ClaimsTransformer.GenerateUserIdentityAsync, // See code of ClaimsTransformer class for details. RedirectToIdentityProvider = n => { n.ProtocolMessage.IdentityProvider = identityOptions.Authority; // The IdP will decide its own best url if this is not set here. return(Task.FromResult(0)); } }; app.UseOpenIdConnectAuthentication(identityOptions); // Don't forget this line and updating the web.config with <add key="owin:appStartup" value="UmbracoCustomOwinStartup" /> }
public void Configuration(IAppBuilder app) { //Configure the Identity user manager for use with Umbraco Back office // *** EXPERT: There are several overloads of this method that allow you to specify a custom UserStore or even a custom UserManager! app.ConfigureUserManagerForUmbracoBackOffice( ApplicationContext.Current, //The Umbraco membership provider needs to be specified in order to maintain backwards compatibility with the // user password formats. The membership provider is not used for authentication, if you require custom logic // to validate the username/password against an external data source you can create create a custom UserManager // and override CheckPasswordAsync global::Umbraco.Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider().AsUmbracoMembershipProvider()); //Ensure owin is configured for Umbraco back office authentication app .UseUmbracoBackOfficeCookieAuthentication(ApplicationContext.Current) .UseUmbracoBackOfficeExternalCookieAuthentication(ApplicationContext.Current); var identityOptions = new OpenIdConnectAuthenticationOptions { ClientId = "u-client-bo", SignInAsAuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType, Authority = "http://localhost:5000", RedirectUri = "http://localhost:5003/umbraco", PostLogoutRedirectUri = "http://localhost:5003/umbraco", ResponseType = "code id_token token", Scope = "openid profile email application.profile application.policy" }; // Configure BackOffice Account Link button and style identityOptions.ForUmbracoBackOffice("btn-microsoft", "fa-windows"); identityOptions.Caption = "OpenId Connect"; // Fix Authentication Type identityOptions.AuthenticationType = "http://localhost:5000"; // Configure AutoLinking identityOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions( autoLinkExternalAccount: true, defaultUserGroups: null, defaultCulture: null )); identityOptions.Notifications = new OpenIdConnectAuthenticationNotifications { SecurityTokenValidated = EnrollUser.GenerateIdentityAsync }; app.UseOpenIdConnectAuthentication(identityOptions); }
public static void ConfigureBackOfficeAzureActiveDirectoryA2BAuth(this IAppBuilder app, string tenant, string clientId, string clientSecret, string redirectUri, string signUpPolicyId, string signInPolicyId, string userProfilePolicyId, string adminClientId, string adminClientSecret, //Guid issuerId, string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows") { //ORIGINAL OPTIONS SUPPLIED BY SAMPLE B2C APP //var options = new OpenIdConnectAuthenticationOptions //{ // // These are standard OpenID Connect parameters, with values pulled from web.config // ClientId = clientId, // RedirectUri = redirectUri, // PostLogoutRedirectUri = redirectUri, // Notifications = new OpenIdConnectAuthenticationNotifications // { // AuthenticationFailed = AuthenticationFailed, // RedirectToIdentityProvider = OnRedirectToIdentityProvider, // }, // Scope = "openid", // ResponseType = "id_token", // // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication // // endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder. // ConfigurationManager = new PolicyConfigurationManager( // string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix), // new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }), // // This piece is optional - it is used for displaying the user's name in the navigation bar. // TokenValidationParameters = new TokenValidationParameters // { // NameClaimType = "name" // }, //}; var adOptions = new OpenIdConnectAuthenticationOptions { ClientId = clientId, RedirectUri = redirectUri, PostLogoutRedirectUri = redirectUri, Notifications = new OpenIdConnectAuthenticationNotifications { //AuthenticationFailed = AuthenticationFailed, RedirectToIdentityProvider = OnRedirectToIdentityProvider, ////When the user is authorized and we are not asking for an id_token (see way below for details on that), //// we will get an auth code which we can then use to retrieve information about the user. //AuthorizationCodeReceived = async notification => //{ // // The user's objectId is extracted from the claims provided in the id_token, and used to cache tokens in ADAL // // The authority is constructed by appending your B2C directory's name to "https://login.microsoftonline.com/" // // The client credential is where you provide your application secret, and is used to authenticate the application to Azure AD // var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; // var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty); // var credential = new ClientCredential(clientId, clientSecret); // // We don't care which policy is used to access the TaskService, so let's use the most recent policy as indicated in the sign-in token // var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value; // // The Authentication Context is ADAL's primary class, which represents your connection to your B2C directory // // ADAL uses an in-memory token cache by default. In this case, we've extended the default cache to use a simple per-user session cache // var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId)); // // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // // The token will be stored in the ADAL token cache, for use in our controllers // var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy); // //var userDetails = await GetUserByObjectId(result, userObjectId, tenant, clientId, clientSecret); // var asdf = result; //}, MessageReceived = notification => { return(Task.FromResult(0)); }, SecurityTokenReceived = notification => { return(Task.FromResult(0)); }, SecurityTokenValidated = notification => { //var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; //var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty); //var credential = new ClientCredential(clientId, clientSecret); // We don't care which policy is used to access the TaskService, so let's use the most recent policy //var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value; // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // AcquireTokenSilentAsync will return a token from the token cache, and throw an exception if it cannot do so. //var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId)); //var result = await authContext.AcquireTokenSilentAsync(new string[] { clientId }, credential, UserIdentifier.AnyUser, mostRecentPolicy); // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // The token will be stored in the ADAL token cache, for use in our controllers //var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy); //var asdf = result; //The returned identity doesn't actually have 'email' as a claim, but instead has a collection of "emails", so we're going to ensure one is // in there and then set the Email claim to be the first so that auto-signin works var emails = notification.AuthenticationTicket.Identity.FindFirst("emails"); if (emails != null) { var email = emails.Value; notification.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Email, email)); } return(Task.FromResult(0)); } }, //NOTE: in this article they are requesting this scope: https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-web-api-dotnet/ // I'm unsure if we leave off the offline_access part if we'd get an authcode request back or not, so leaving it here // for now since it is working. //Scope = "openid offline_access", Scope = "openid", //NOTE: If we ask for this, then we'll simply get an ID Token back which we cannot use to request // additional data of the user. We need to get an authorization code reponse (I'm not sure what the // string value for that is but if we don't specify then it's the default). ResponseType = "id_token", // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication // endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder. // The first parameter is the metadata URL of your B2C directory // The second parameter is an array of the policies that your app will use. ConfigurationManager = new PolicyConfigurationManager( string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix), new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }), // This piece is optional - it is used for displaying the user's name in the navigation bar. TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", }, SignInAsAuthenticationType = Umbraco.Core.Constants.Security.BackOfficeExternalAuthenticationType }; adOptions.SetChallengeResultCallback(context => new AuthenticationProperties( new Dictionary <string, string> { { UmbracoADAuthExtensions.PolicyKey, signInPolicyId } }) { RedirectUri = "/Umbraco", }); var orig = adOptions.AuthenticationType; adOptions.ForUmbracoBackOffice(style, icon); adOptions.AuthenticationType = orig; adOptions.Caption = caption; //NOTE: This needs to be set after the ForUmbracoBackOffice // this needs to be set to what AD returns otherwise you cannot unlink an account adOptions.AuthenticationType = string.Format( CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/v2.0/", //Not sure where this comes from! ... perhaps 'issuerId', but i don't know where to find this, // i just know this based on the response we get from B2C "ae25bf5e-871e-454a-a1b6-a3560a09ec5e"); //This will auto-create users based on the authenticated user if they are new //NOTE: This needs to be set after the explicit auth type is set adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: true)); app.UseOpenIdConnectAuthentication(adOptions); }
public static void ConfigureBackOfficeAzureActiveDirectoryA2BAuth(this IAppBuilder app, string tenant, string clientId, string clientSecret, string redirectUri, string signUpPolicyId, string signInPolicyId, string userProfilePolicyId, string adminClientId, string adminClientSecret, //Guid issuerId, string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows") { //ORIGINAL OPTIONS SUPPLIED BY SAMPLE B2C APP //var options = new OpenIdConnectAuthenticationOptions //{ // // These are standard OpenID Connect parameters, with values pulled from web.config // ClientId = clientId, // RedirectUri = redirectUri, // PostLogoutRedirectUri = redirectUri, // Notifications = new OpenIdConnectAuthenticationNotifications // { // AuthenticationFailed = AuthenticationFailed, // RedirectToIdentityProvider = OnRedirectToIdentityProvider, // }, // Scope = "openid", // ResponseType = "id_token", // // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication // // endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder. // ConfigurationManager = new PolicyConfigurationManager( // string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix), // new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }), // // This piece is optional - it is used for displaying the user's name in the navigation bar. // TokenValidationParameters = new TokenValidationParameters // { // NameClaimType = "name" // }, //}; var adOptions = new OpenIdConnectAuthenticationOptions { ClientId = clientId, RedirectUri = redirectUri, PostLogoutRedirectUri = redirectUri, Notifications = new OpenIdConnectAuthenticationNotifications { //AuthenticationFailed = AuthenticationFailed, RedirectToIdentityProvider = OnRedirectToIdentityProvider, ////When the user is authorized and we are not asking for an id_token (see way below for details on that), //// we will get an auth code which we can then use to retrieve information about the user. //AuthorizationCodeReceived = async notification => //{ // // The user's objectId is extracted from the claims provided in the id_token, and used to cache tokens in ADAL // // The authority is constructed by appending your B2C directory's name to "https://login.microsoftonline.com/" // // The client credential is where you provide your application secret, and is used to authenticate the application to Azure AD // var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; // var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty); // var credential = new ClientCredential(clientId, clientSecret); // // We don't care which policy is used to access the TaskService, so let's use the most recent policy as indicated in the sign-in token // var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value; // // The Authentication Context is ADAL's primary class, which represents your connection to your B2C directory // // ADAL uses an in-memory token cache by default. In this case, we've extended the default cache to use a simple per-user session cache // var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId)); // // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // // The token will be stored in the ADAL token cache, for use in our controllers // var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy); // //var userDetails = await GetUserByObjectId(result, userObjectId, tenant, clientId, clientSecret); // var asdf = result; //}, MessageReceived = notification => { return Task.FromResult(0); }, SecurityTokenReceived = notification => { return Task.FromResult(0); }, SecurityTokenValidated = notification => { //var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; //var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty); //var credential = new ClientCredential(clientId, clientSecret); // We don't care which policy is used to access the TaskService, so let's use the most recent policy //var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value; // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // AcquireTokenSilentAsync will return a token from the token cache, and throw an exception if it cannot do so. //var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId)); //var result = await authContext.AcquireTokenSilentAsync(new string[] { clientId }, credential, UserIdentifier.AnyUser, mostRecentPolicy); // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId. // The token will be stored in the ADAL token cache, for use in our controllers //var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy); //var asdf = result; //The returned identity doesn't actually have 'email' as a claim, but instead has a collection of "emails", so we're going to ensure one is // in there and then set the Email claim to be the first so that auto-signin works var emails = notification.AuthenticationTicket.Identity.FindFirst("emails"); if (emails != null) { var email = emails.Value; notification.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Email, email)); } return Task.FromResult(0); } }, //NOTE: in this article they are requesting this scope: https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-web-api-dotnet/ // I'm unsure if we leave off the offline_access part if we'd get an authcode request back or not, so leaving it here // for now since it is working. //Scope = "openid offline_access", Scope = "openid", //NOTE: If we ask for this, then we'll simply get an ID Token back which we cannot use to request // additional data of the user. We need to get an authorization code reponse (I'm not sure what the // string value for that is but if we don't specify then it's the default). ResponseType = "id_token", // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication // endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder. // The first parameter is the metadata URL of your B2C directory // The second parameter is an array of the policies that your app will use. ConfigurationManager = new PolicyConfigurationManager( string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix), new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }), // This piece is optional - it is used for displaying the user's name in the navigation bar. TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", }, SignInAsAuthenticationType = Umbraco.Core.Constants.Security.BackOfficeExternalAuthenticationType }; adOptions.SetChallengeResultCallback(context => new AuthenticationProperties( new Dictionary<string, string> { {UmbracoADAuthExtensions.PolicyKey, signInPolicyId} }) { RedirectUri = "/Umbraco", }); var orig = adOptions.AuthenticationType; adOptions.ForUmbracoBackOffice(style, icon); adOptions.AuthenticationType = orig; adOptions.Caption = caption; //NOTE: This needs to be set after the ForUmbracoBackOffice // this needs to be set to what AD returns otherwise you cannot unlink an account adOptions.AuthenticationType = string.Format( CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/v2.0/", //Not sure where this comes from! ... perhaps 'issuerId', but i don't know where to find this, // i just know this based on the response we get from B2C "ae25bf5e-871e-454a-a1b6-a3560a09ec5e"); //This will auto-create users based on the authenticated user if they are new //NOTE: This needs to be set after the explicit auth type is set adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: true)); app.UseOpenIdConnectAuthentication(adOptions); }
/// <summary> /// Configure ActiveDirectory sign-in /// </summary> /// <param name="app"></param> /// <param name="tenant"> /// Your tenant ID i.e. YOURDIRECTORYNAME.onmicrosoft.com OR this could be the GUID of your tenant ID /// </param> /// <param name="clientId"> /// Also known as the Application Id in the azure portal /// </param> /// <param name="postLoginRedirectUri"> /// The URL that will be redirected to after login is successful, example: http://mydomain.com/umbraco/; /// </param> /// <param name="issuerId"> /// This is the "Issuer Id" for you Azure AD application. This is a GUID value of your tenant ID. /// If this value is not set correctly then accounts won't be able to be detected /// for un-linking in the back office. /// </param> /// <param name="caption"></param> /// <param name="style"></param> /// <param name="icon"></param> /// <remarks> /// ActiveDirectory account documentation for ASP.Net Identity can be found: /// https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet /// </remarks> public static void ConfigureBackOfficeAzureActiveDirectoryAuth(this IAppBuilder app, string tenant, string clientId, string postLoginRedirectUri, Guid issuerId, string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows") { var authority = string.Format( CultureInfo.InvariantCulture, "https://login.windows.net/{0}", tenant); var adOptions = new OpenIdConnectAuthenticationOptions { AuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType, ClientId = clientId, Authority = authority, RedirectUri = postLoginRedirectUri, Notifications = new OpenIdConnectAuthenticationNotifications { AuthorizationCodeReceived = async context => { var userService = Current.Services.UserService; var email = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("unique_name")).Value; var issuer = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("iss")).Value; var providerKey = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("sub")).Value; var userManager = context.OwinContext.GetUserManager <BackOfficeUserManager>(); var user = userService.GetByEmail(email); if (user == null) { Log.Logger.Error($"The user {email} does not exist in Umbraco."); return; } var identity = await userManager.FindByEmailAsync(email); var identityClaims = await userManager.GenerateUserIdentityAsync(identity); context.OwinContext.Authentication.SignIn(identityClaims); //if (identity.Logins.All(x => { // return !x.ProviderKey.Equals(providerKey); //})) //{ // identity.Logins.Add(new IdentityUserLogin(issuer, providerKey, user.Id)); // await userManager.UpdateAsync(identity); //} } } }; adOptions.ForUmbracoBackOffice(style, icon); adOptions.Caption = caption; //adOptions.AuthenticationType = string.Format( // CultureInfo.InvariantCulture, // "https://sts.windows.net/{0}/", // issuerId); app.UseOpenIdConnectAuthentication(adOptions); adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(true)); }