2016-04-08 31 views
5

Configurazione di un'app Web che utilizza ADFS, per questo utilizzo OWIN.SSO con AD FS e OWIN come creare un account e gestire le autorizzazioni

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

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

quindi voglio controllare che un utente esiste nel mio database con questo account AD (questo processo sarà fanno prima del login in un'altra applicazione)

voglio usare identità da Microsoft per la gestione dei sinistri (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 
       //{ 

       //} 
      }); 

    } 

Nel web.config, regno è il link al mio Web App (https://ssoadfs.test) e adfsMetadata è il link per metadata.xml da AD FS.

Qual è la modalità da seguire per impostare il ruolo e la logica di accesso dopo la connessione AD FS?

schema che quello che stavo pensando:

enter image description here

EDIT: Dopo alcuni tentativi, non riesco a gestire qualsiasi callback successo. Io non voglio avere a gestire ruoli in HomeController ...

Il mio ultimo Auth config:

  _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>(ApplicationUserManager.Create); 
     app.CreatePerOwinContext<ApplicationSignInManager>(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<ApplicationUserManager, ApplicationUser>(
        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<long>)user == (Entity<long>)null) 
         //  LoginResult = new ApplicationUserManager.LoginResult(LoginResultType.InvalidUserNameOrEmailAddress, default(IUser)); 
         // //else if (!loggedInFromExternalSource && new PasswordHasher().VerifyHashedPassword(user.Password, plainPassword) != PasswordVerificationResult.Success) 
         // // LoginResult = new UserManager<TTenant, TRole, TUser>.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 cercato CallbackPath (nulla è apparso nel mio log), WsFederationAuthenticationNotifications.SecurityTokenValidated (nulla è apparso nel mio log), CookieAuthenticationProvider.OnResponseSignIn (lo stesso non è successo niente)

in HomeController io sono in grado di avere Identity.Name:

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

     return View(); 
    } 

Mi sono perso qualcosa per ricevere notifiche o provider in CookieAuthenticationOptions ???

+0

Utilizzando AD e identità non e fuori l'opzione di dialogo è. Sei bloccato a creare quella funzionalità. Sono necessarie 2 istanze UserManager configurate in modo distinto ... –

+0

È possibile eliminare le "2 istanze di UserManager"? Per ora, penso di creare un'API Wep che funzioni con AD WS-Federation (ancora da fare) e quindi chiamare il metodo anoher con il cookie per verificare se l'utente esiste nel Database come utente. – Jerome2606

+0

@ user18620 Ciao, non proprio una soluzione ... ma lo controllo in AccountController.AuthenticationCallbackAD() impostando il percorso predefinito in App_Start/RouteConfig. All'interno di questo metodo creo l'utente o controllo se è convalidato utilizzando UserManager Identità ASP.NET. E aggiungi reclami personalizzati. – Jerome2606

risposta

1

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

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> 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=******", "[email protected]om", "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 aiuti ...

+0

Ciao Murat, grazie al tentativo di aiutarmi. Ma il mio problema è più che non riesco a gestire una richiamata nel modo giusto di OWIN. Non passerò mai in una pagina di accesso perché è un'applicazione SSO (quindi l'utente è autenticato da Owin prima di entrare nella mia Applicazione). Per ora, aggiungo la logica in HomeController per verificare se l'utente è autenticato, quindi aggiungo utente in UserManager ... :( – Jerome2606

+0

Sei benvenuto Jerome. Non riuscivo a capire perché il tuo usato HomeController invece di AccountController? D'altra parte, se tu avere abbastanza tempo e non utilizzare ASP.NET Identity 2.0 o versioni successive, si potrebbe dare un'occhiata agli articoli come [ASP.NET MVC e Identity 2.0: Nozioni di base sulle basi] (http://www.codeproject.com/Articles/762428/ASP-NET-MVC-and-Identity-Understanding-the-Basics). Buona fortuna :) –

+0

Uso AspNet.Identity.Core, .EntityFramework, .Owin. Ma mi piacerebbe utilizzare ADFS e Owin, per semplificare la configurazione (necessario solo il metadata.xml da AD). Io uso un codice simile al tuo con UserManager di Identity e non è una scelta per aggiungere questa logica in HomeController. Potrei metterlo in AccountController con la definizione del percorso predefinito. Ma sono sicuro che Owin può aiutarmi a gestirlo in Avvio autenticazione Config – Jerome2606