SSO con AD FS e OWIN come creare un account e gestire le autorizzazioni

Configurazione un’app Web che utilizza ADFS, per questo utilizzo OWIN.

Per il login, tutto è ok. Se sono un utente di un dominio e vado al sito web, viene automaticamente connesso.

Ma quello che voglio avere è di gestire utenti e ruoli da solo dopo il login.

Quindi voglio verificare che un utente esista nel mio database con questo account AD (questo processo sarà effettuato prima del login in un’altra applicazione)

Voglio usare Identity di Microsoft per gestire le attestazioni (ruoli e permessi). Ma non capisco come mettere il mio codice per gestire la connessione di successo da ADFS (con Ws-Federation) e aggiungere la verifica e inserire i ruoli giusti.

Il mio codice in ConfigureAuth:

public partial class Startup { private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"]; private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"]; private NLogLoggingService _loggingService; public void ConfigureAuth(IAppBuilder app) { _loggingService = new NLogLoggingService("Startup"); _loggingService.Debug("ConfigureAuth"); app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseWsFederationAuthentication( new WsFederationAuthenticationOptions { Wtrealm = realm, MetadataAddress = adfsMetadata, //CallbackPath = PathString.FromUriComponent("/Account/TestCallback"), // https://msdn.microsoft.com/en-us/library/microsoft.owin.security.authenticationmode(v=vs.113).aspx AuthenticationMode = AuthenticationMode.Passive, //Notifications = new WsFederationAuthenticationNotifications //{ //} }); } 

In Web.config, realm è il collegamento alla mia app Web ( https: //ssoadfs.test ) e adfsMetadata è il collegamento a metadata.xml di ADFS.

Qual è la strada da percorrere per impostare il mio ruolo e la logica di accesso dopo la connessione AD FS?

Schema quello che stavo pensando:

inserisci la descrizione dell'immagine qui

EDIT: dopo alcuni tentativi, non riesco a gestire alcuna callback di successo. Non voglio dover gestire i ruoli in HomeController …

La mia ultima configurazione di Auth:

  _loggingService = new NLogLoggingService("Startup"); _loggingService.Debug("ConfigureAuth"); // Configure the db context, user manager and signin manager to use a single instance per request app.CreatePerOwinContext(ApplicationUser.ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); app.CreatePerOwinContext(ApplicationSignInManager.Create); app.SetDefaultSignInAsAuthenticationType(DefaultAuthenticationTypes.ApplicationCookie); app.UseCookieAuthentication(new CookieAuthenticationOptions { Provider = new CookieAuthenticationProvider { OnResponseSignIn = ctx => { _loggingService.Debug("OnResponseSignIn"); ctx.Identity = TransformClaims(ctx, app); }, // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); app.UseWsFederationAuthentication( new WsFederationAuthenticationOptions { Wtrealm = realm, MetadataAddress = adfsMetadata, Caption = "Active Directory", CallbackPath = PathString.FromUriComponent("/Account/TestCallback"), Notifications = new WsFederationAuthenticationNotifications { SecurityTokenValidated = n => { new NLogLoggingService("Startup").Debug("SecurityTokenValidated"); var incomingClaimsFromAdfs = n.AuthenticationTicket.Identity.Claims.ToList(); var incomingClaimsHasNameIdentifier = incomingClaimsFromAdfs.Any( c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier); _loggingService.Debug("SecurityTokenValidated - incomingClaimsHasNameIdentifier: " + incomingClaimsHasNameIdentifier); if (!incomingClaimsHasNameIdentifier) { var emailClaim = incomingClaimsFromAdfs.First(c => c.Type == System.Security.Claims.ClaimTypes.Name); _loggingService.Debug(emailClaim.Value); } //if (!incomingClaimsHasNameIdentifier) //{ // var emailClaim = incomingClaimsFromAdfs.First(c => c.Type == System.Security.Claims.ClaimTypes.Name); // incomingClaimsFromAdfs.Add(); // IUser user = await this.UserStore.FindByNameOrEmailAsync(userNameOrEmailAddress); // if ((Entity)user == (Entity)null) // LoginResult = new ApplicationUserManager.LoginResult(LoginResultType.InvalidUserNameOrEmailAddress, default(IUser)); // //else if (!loggedInFromExternalSource && new PasswordHasher().VerifyHashedPassword(user.Password, plainPassword) != PasswordVerificationResult.Success) // // LoginResult = new UserManager.LoginResult(LoginResultType.InvalidPassword, user); // else // LoginResult = await this.CreateLoginResultAsync(user, tenant); //} //else //{ // throw new ApplicationException("Get ADFS to provide the NameIdentifier claim!"); //} //var normalizedClaims = incomingClaimsFromAdfs.Distinct(new ClaimComparer()); //var claimsIdentity = new ClaimsIdentity(normalizedClaims, n.AuthenticationTicket.Identity.AuthenticationType); //n.AuthenticationTicket = new AuthenticationTicket(claimsIdentity, n.AuthenticationTicket.Properties); return Task.FromResult(0); } } }); 

In questo codice, ho provato CallbackPath (niente è apparso nel mio log), WsFederationAuthenticationNotifications.SecurityTokenValidated (niente è apparso nel mio log), CookieAuthenticationProvider.OnResponseSignIn (non è successo niente)

Sono in grado di avere Identity.Name in HomeController:

 public ActionResult Index() { if (HttpContext.GetOwinContext().Authentication.User.Identity.IsAuthenticated) { new NLogLoggingService("Home").Debug("User is authenticated"); } return View(); } 

Ho perso qualcosa per ricevere notifiche o provider in CookieAuthenticationOptions ???

    Se si utilizza ASP.NET Identity 2.0 o versione successiva, è ansible utilizzare un approccio simile a quello illustrato di seguito. Si noti che questo approccio assegna GroupRoles all’utente invece di assegnare ognuno dei ruoli uno per uno. È ansible modificare le parti necessarie in base alle proprie esigenze.

     [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } ApplicationGroupManager groupManager = new ApplicationGroupManager(); if (Membership.ValidateUser(model.UserName, model.Password)) { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); //Assign Roles to the current User ApplicationUser user = UserManager.FindByName(model.UserName); //If the user is registered in the system (ASP.NET Identity) add record to AspNetUsers table if (user != null) { //Returns Group Id and Role Id by using User Id parameter var userGroupRoles = groupManager.GetUserGroupRoles("bfd9730e-2093-4fa0-89a2-226e301d831b"); foreach (var role in userGroupRoles) { string roleName = RoleManager.FindById(role.ApplicationRoleId).Name; UserManager.AddToRole(user.Id, roleName); } } else { //crate new user //first retrieve user info from LDAP: // Create an array of properties that we would like and add them to the search object string[] requiredProperties = new string[] { "samaccountname", "givenname", "sn", "mail", "physicalDeliveryOfficeName", "title" }; var userInfo = CreateDirectoryEntry(model.UserName, requiredProperties); var newUser = new ApplicationUser(); newUser.UserName = userInfo.GetDirectoryEntry().Properties["samaccountname"].Value.ToString(); newUser.Name = userInfo.GetDirectoryEntry().Properties["givenname"].Value.ToString(); newUser.Surname = userInfo.GetDirectoryEntry().Properties["sn"].Value.ToString(); newUser.Email = userInfo.GetDirectoryEntry().Properties["mail"].Value.ToString(); newUser.EmailConfirmed = true; newUser.PasswordHash = null; var result = await UserManager.CreateAsync(newUser); if (result.Succeeded) { //If the user is created ... } //Assign user group (and roles) var defaultGroup = "751b30d7-80be-4b3e-bfdb-3ff8c13be05e"; groupManager.SetUserGroups(newUser.Id, new string[] { defaultGroup }); } return this.RedirectToAction("Index", "Issue"); } this.ModelState.AddModelError(string.Empty, "Wrong username or password!"); return this.View(model); } static SearchResult CreateDirectoryEntry(string sAMAccountName, string[] requiredProperties) { DirectoryEntry ldapConnection = null; try { ldapConnection = new DirectoryEntry("LDAP://OU=******, DC=******, DC=******", "acb@xyz.com", "YourPassword"); ldapConnection.AuthenticationType = AuthenticationTypes.Secure; DirectorySearcher search = new DirectorySearcher(ldapConnection); search.Filter = String.Format("(sAMAccountName={0})", sAMAccountName); foreach (String property in requiredProperties) search.PropertiesToLoad.Add(property); SearchResult result = search.FindOne(); //SearchResultCollection searchResultCollection = search.FindAll(); //You can also retrieve all information if (result != null) { return result; } else { return null; //Console.WriteLine("User not found!"); } } catch (Exception e) { Console.WriteLine("Exception caught:\n\n" + e.ToString()); } return null; } 

    Spero che questo ti aiuti…