Open Closed

LDAP auto signIn to application / no passwor need #504


0
klainer created

Hello, I have question, how auto SignIn user with LDAP auth source. User no need password only his windows username, so if logged to windows is automticly logged to application / no login form need.

Where can i put this logic ? SignIn method in ABP need password / i do not have it because I can not get it from Windows...

Scenario:

1)User is logged in windows 2)User start brower with aplication 3) Aplication get windows username ang check if username exist in LDAP server 4) If it is OK - user is logged, / (ABP framework create record about user in AbpUser table (if not exist) -- this only for permission and role managment).

I have one idea to use Login(username, pass) method from Form base auth, and after user come to page and is logged by windows auth, perform this method in base constructor of controller using windows username (if LDAP auth do not have this username auth failded and user is redirected) Do you have better solution ? Is redirection possible in constructor of Controller ?

I also tried enable windows auth -> enable in web.config. But I got this error: Request filtering is configured on the Web server to deny the request because the query string is too long.

Is even posible to use windows auth with ABP and LDAP and Abp.User / Roles table ?

Thanks for help!

PS: Small question. What if I want to grand permissions for users in ActiveDirecotry db / in AbpUser is single record showed after login. Active Directory have xxxx users?


24 Answer(s)
  • 0
    klainer created

    Hello, I created sample project with my problem and solution of it. Project is based on: ABP + ZERO + OWIN Mixed Auth: <a class="postlink" href="https://mega.nz/#!DUMgAD7A!tCX0MeHbYA88WGfj4clgcBE97HixrtaqPaH9N51d8f4">https://mega.nz/#!DUMgAD7A!tCX0MeHbYA88 ... aH9N51d8f4</a>

    Please somebody have little time and test my SAMPLE auto windows login project, I will be pleased. I have problem with redirection loop when signin / sign out.

    Thanks hikalkan !

  • 0
    hikalkan created
    Support Team

    Hi,

    I think you want to single sign on. I don't know how to check windows auth since I have no much experience. But, for ABP;

    Check <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero-template/blob/master/src/AbpCompanyName.AbpProjectName.WebSpaAngular/Controllers/AccountController.cs#L111">https://github.com/aspnetboilerplate/mo ... er.cs#L111</a>

    As you see this method Sign in without a password. Just get a user from database (from usermanager) and sign in.

    I opened your solution but got error. Can you guide me where to check?

    Thanks.

  • 0
    klainer created

    Hello, thanks.

    I crated new issue there, and I found bug probably and his probable cause. See there: <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/issues/714">https://github.com/aspnetboilerplate/as ... issues/714</a>

    Sample project was updated, link is on git issue.

    BTW: Where would you paste code to auto SignIn when User starts the application ? I can get UserName from current thread and sign on using your method with db. But I´m not sure where paste this logic.

    Thanks!

  • 0
    hikalkan created
    Support Team

    Hi,

    I will check the issue. Thanks.

    Just make it on Login action. Because it goes to Account/Login if user has not logged in. So, you can write the auto-login and redirect login inside it. Notice that there are two logins. You will use the one returns the Login View normally.

  • 0
    klainer created

    Hello, I did it like you wrote. Burt htere is little problem, I must enable Windows Auth in project, but when I enable it in web config by:

    <system.web>

    &lt;authentication mode=&quot;Windows&quot; /&gt;
    &lt;authorization&gt;
      &lt;deny users=&quot;?&quot; /&gt;
    &lt;/authorization&gt;
    

    I got this error:

    Request filtering module is configured to deny the request, the query string is too long.

    Detailed Error Information: Module RequestFilteringModule Notification BeginRequest Handler ExtensionlessUrlHandler-Integrated-4.0 Error Code 0x00000000

    Requested URL	   http://localhost:6334/Account/Login?ReturnUrl=%2FAccount%2FLogin%3FReturnUrl%3D%252FAccount%252FLogin%253FReturnUrl%253D%25252FAccount%25252FLogin%25253FReturnUrl%25253D%2525252FAccount%2525252FLogin%2525253FReturnUrl%2525253D%252525252FAccount%252525252FLogin%252525253FReturnUrl%252525253D%25252525252FAc.......
    

    Thanks for help

  • 0
    hikalkan created
    Support Team

    I think you have a recursive redirect which adds querystring in every redirect. You can add breakpoint to understand why it redirects.

  • 0
    klainer created

    It sems that problem is with owin.

    When I enebale windows auth and disable allow anonymus - I need the windows login form. I need to login user based on his windows account automaticly and use your ABP roles managment, ABPAuthorize .... I have no idea how to solve this

  • 0
    klainer created

    When I=m creating user by your method i got this error (only on IE, chrome works with out error (this I do not understand)):

    V aplikaci / došlo k chybě serveru.
    
    Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values. 
      Popis: Při provádění aktuálního webového požadavku došlo k neošetřené výjimce. Další informace o chybě a o jejím původu v kódu naleznete v trasování zásobníku. 
    
     Podrobnosti o výjimce: System.Data.Entity.Core.UpdateException: Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
    
    Zdrojová chyba: 
    
    
    
    Řádek 475:                    Logger.Debug("Vytváření uživatele: " + createUser.UserName);
    Řádek 476:
    Řádek 477:                    var newUser = _userManager.Create(createUser);
    Řádek 478:
    Řádek 479:                    Logger.Debug("Konec vytváření uživatele: ");
      
    
     Zdrojový soubor:  C:\Projects\\TT.Web\Controllers\AccountController.cs    Řádek:  477
    

    I must create manual insert by this code to get it work. Create user with user manager have error above...

    SqlCommand command = new SqlCommand(
                    "INSERT INTO [AbpUsers] ([TenantId] ,[AuthenticationSource],[Name],[Surname],[UserName],[Password] ,[EmailAddress]"+
                    ",[IsEmailConfirmed],[EmailConfirmationCode],[PasswordResetCode] ,[LastLoginTime],[IsActive],[IsDeleted],[DeleterUserId]" +
                    ",[DeletionTime] ,[LastModificationTime],[LastModifierUserId],[CreationTime],[CreatorUserId] ,[Company] )" +
                    "VALUES ( @TenantId, @AuthenticationSource, @Name, @Surname, @UserName, @Password, @EmailAddress, @IsEmailConfirmed, @EmailConfirmationCode , @PasswordResetCode, " +
                    "@LastLoginTime, @IsActive, @IsDeleted, @DeleterUserId, @DeletionTime, @LastModificationTime , @LastModifierUserId, @CreationTime," +
                    "@CreatorUserId, @Company ); SELECT SCOPE_IDENTITY();");
    
                SqlParameter parameter3 = new SqlParameter { DbType = DbType.Int32, ParameterName = "@TenantId", Value = 1 };
                SqlParameter parameter4 = new SqlParameter { DbType = DbType.String, ParameterName = "@AuthenticationSource", Value = DBNull.Value };
                SqlParameter parameter5 = new SqlParameter { DbType = DbType.String, ParameterName = "@Name", Value = createUser2.UserName };
                SqlParameter parameter6 = new SqlParameter { DbType = DbType.String, ParameterName = "@Surname", Value = createUser2.UserName };
                SqlParameter parameter7 = new SqlParameter { DbType = DbType.String, ParameterName = "@UserName", Value = createUser2.UserName };
                SqlParameter parameter8 = new SqlParameter { DbType = DbType.String, ParameterName = "@Password", Value = createUser2.UserName };
                SqlParameter parameter9 = new SqlParameter { DbType = DbType.String, ParameterName = "@EmailAddress", Value = createUser2.UserName };
                SqlParameter parameter10 = new SqlParameter { DbType = DbType.Boolean, ParameterName = "@IsEmailConfirmed", Value = true };
                SqlParameter parameter11 = new SqlParameter { DbType = DbType.String, ParameterName = "@EmailConfirmationCode", Value = DBNull.Value };
                SqlParameter parameter12 = new SqlParameter { DbType = DbType.String, ParameterName = "@PasswordResetCode", Value = DBNull.Value };
                SqlParameter parameter13 = new SqlParameter { DbType = DbType.DateTime, ParameterName = "@LastLoginTime", Value = DBNull.Value };
                SqlParameter parameter14 = new SqlParameter { DbType = DbType.Boolean, ParameterName = "@IsActive", Value = true };
                SqlParameter parameter15 = new SqlParameter { DbType = DbType.Boolean, ParameterName = "@IsDeleted", Value = false };
                SqlParameter parameter16 = new SqlParameter { DbType = DbType.Int32, ParameterName = "@DeleterUserId", Value = DBNull.Value };
                SqlParameter parameter17 = new SqlParameter { DbType = DbType.DateTime, ParameterName = "@DeletionTime", Value = DBNull.Value };
                SqlParameter parameter18 = new SqlParameter { DbType = DbType.DateTime, ParameterName = "@LastModificationTime", Value = DBNull.Value };
                SqlParameter parameter19 = new SqlParameter { DbType = DbType.Int32, ParameterName = "@LastModifierUserId", Value = DBNull.Value };
                SqlParameter parameter20 = new SqlParameter { DbType = DbType.DateTime, ParameterName = "@CreationTime", Value = DateTime.Now };
                SqlParameter parameter21 = new SqlParameter { DbType = DbType.Int32, ParameterName = "@CreatorUserId", Value = 2 };
                SqlParameter parameter22 = new SqlParameter { DbType = DbType.String, ParameterName = "@Company", Value = createUser2.Com };
    
                command.Parameters.Add(parameter3);
                command.Parameters.Add(parameter4);
                command.Parameters.Add(parameter5);
                command.Parameters.Add(parameter6);
                command.Parameters.Add(parameter7);
                command.Parameters.Add(parameter8);
                command.Parameters.Add(parameter9);
                command.Parameters.Add(parameter10);
                command.Parameters.Add(parameter11);
                command.Parameters.Add(parameter12);
                command.Parameters.Add(parameter13);
                command.Parameters.Add(parameter14);
                command.Parameters.Add(parameter15);
                command.Parameters.Add(parameter16);
                command.Parameters.Add(parameter17);
                command.Parameters.Add(parameter18);
                command.Parameters.Add(parameter19);
                command.Parameters.Add(parameter20);
                command.Parameters.Add(parameter21);
                command.Parameters.Add(parameter22);
    
  • 0
    hans abelshausen created

    Hi, we have similar problems. What is the right way to activate sso without getting thousands of redirects to login form? Thanks in advance

  • 0
    klainer created

    Hello I finaly used Mixed Auth project for owin windows SSO. (<a class="postlink" href="https://github.com/MohammadYounes/OWIN-MixedAuth">https://github.com/MohammadYounes/OWIN-MixedAuth</a>)

    I had to create MySession class which extended base AbpSession class, because I have problem with UserId property which is not setted.

    public class MySession : ClaimsAbpSession
        {
    
            public MySession(IMultiTenancyConfig multiTenancy) : base(multiTenancy)
            {
            }
    
            protected object ExecuteScalar(SqlCommand command)
            {
                object obj2;
                using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString))
                {
                    connection.Open();
                    command.Connection = connection;
                    using (command)
                    {
                        obj2 = command.ExecuteScalar();
                    }
                    connection.Close();
                }
                return obj2;
            }
    
            public override long? UserId
            {
                get
                {
                    var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
                    if (claimsPrincipal == null)
                    {
                        return null;
                    }
    
                    var claimsIdentity = claimsPrincipal.Identity as WindowsIdentity;
                    if (claimsIdentity == null)
                    {
                        return base.UserId;
                    }
    
                    if (claimsIdentity.Name == "")
                    {
                        return null;
                    }
    
                    SqlCommand command = new SqlCommand("SELECT Id from AbpUsers where UserName = @UserName AND IsDeleted = 0; SELECT SCOPE_IDENTITY();");
                    SqlParameter parmaeter = new SqlParameter { DbType = DbType.String, ParameterName = "@UserName", Value = claimsIdentity.Name };
                    command.Parameters.Add(parmaeter);
                    var vyseldek = Convert.ToInt32(ExecuteScalar(command));
    
                    return vyseldek;
                }
            }
        }
    

    I got user id from DB by his windows Indentity name.

    In web module preIntialize method: IocManager.Register<IAbpSession, MySession>();

    Anonymus auth must be enabled in Web project , ofcourse windows auth too.

    This is my solution, if you have better way share it.

  • 0
    hikalkan created
    Support Team

    Hi,

    Thanks for sharing your solution. I suggest you to create a cache mechanism for performance reason since IAbpSession.UserId is get frequently.

    Have a nice day.

  • 0
    princeppy created

    Hi,

    Please help, source code in <a class="postlink" href="https://github.com/princeppy/DISMetroUIPortal">https://github.com/princeppy/DISMetroUIPortal</a>

    I have followed hikalkan, and created a project.
    When I click on windows button on and it takes to registration page, and when i submit it throwing an error page.

  • 0
    princeppy created

  • 0
    byteplatz created

    I would avoid windows authentication (its not designed for SSO). Instead you should use WS-Federation External Auth (It works fine with Abp, we have it in place).

    Then you can use either AzureAD + Sync with your internal AD OR Install ADFS (Active Directory Federated Services) and use Abp with OWIN/External Auth WS-Federation ...

    This is the standard for the SSO on windows

    Bruno

  • 0
    byteplatz created

    One more catch, if you use WS-Federation + ADFS (or AzureAD) you don't need LDAP Auth. ADFS does that for you

    Bruno

  • 0
    hans abelshausen created

    I'm using SSO like Klainer described. My problem is, if I try to login with SSO and if user not found, I'll try to login with username and password of the application. I get user from db, but in my controller abp.session.userId is undefined. If I log in directly after start of the application with username and password, userId is set.

  • 0
    bagy88 created

    <cite>bytePlatz: </cite> One more catch, if you use WS-Federation + ADFS (or AzureAD) you don't need LDAP Auth. ADFS does that for you

    Bruno

    Hy :)

    I seen that you have some implementation for ADFS. Is it a problem to share your implementation? :)

    Tnx :)

  • 0
    bbakermmc created

    I see this is now part of the Paid version, will this be release to the free version anytime soon?

  • 0
    bbakermmc created

    I see this is now in the Paid version, will this be released to the Free version any time soon?

  • 0
    ismcagdas created
    Support Team

    Hi,

    It's not something hard actually.

    1 ) Add a reference to Microsoft.Owin.Security.WsFederation to your project. 2 ) in Startup.cs use

    app.UseWsFederationAuthentication(CreateWsFederationAuthOptions());
    
    private static WsFederationAuthenticationOptions CreateWsFederationAuthOptions()
    {
        _settingManager = IocManager.Instance.Resolve<ISettingManager>();
        var websiteAddress = _settingManager.GetSettingValue(AppSettings.General.WebSiteRootAddress);
    
        var wtrealm = ConfigurationManager.AppSettings["ExternalAuth.WsFederation.Wtrealm"];
        var metaDataAddress = ConfigurationManager.AppSettings["ExternalAuth.WsFederation.MetaDataAddress"];
    
        return new WsFederationAuthenticationOptions
        {
            Wtrealm = wtrealm,
            MetadataAddress = metaDataAddress,
            AuthenticationType = "adfs",
            Notifications = new WsFederationAuthenticationNotifications
            {
                RedirectToIdentityProvider = notification =>
                {
                    if (notification.ProtocolMessage.IsSignOutMessage)
                    {
                        notification.HandleResponse();
                    }
    
                    notification.ProtocolMessage.Wreply = websiteAddress.EnsureEndsWith('/') + "Account/ExternalLoginCallback";
    
                    return Task.FromResult(0);
                },
                SecurityTokenValidated = notification =>
                {
                    var email = notification.AuthenticationTicket.Identity.Name;
                    notification.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Email, email));
                    return Task.FromResult(0);
                }
            }
        };
    }
    

    Then you can use it like any other external login. You just need to create an icon for this in order to use in your login page.

  • 0
    bbakermmc created

    Are you able to provide a full solution based off the free aspnetboilerplate template? Ive tried using what you proposed and it doesnt work. When you hit the base url of the site in the "Home" controller it goes in to a ADFS redirection loop instead of redirecting me to login page. If I got to the /Account/Login, I see the "ADFS" button, but when I click it, it just redirects me back to login page. The loginInfo in "ExternalLoginCallback" is null.

    Do I need to set some IIS setting like FormsAuth? Disable anonymous or something?

    Update: If I set IIS to allow FormsAuth using "/Account/Login" then when I hit the authorize link in the home controller, I get redirected to the login page.

    If I Have windows auth enabled. When I hit the home controller I get a ADFS redirection loop instead of being redirected to the login page, however, if I goto the login page directly I am able to use the button properly and it logs in just fine as long as my username matches my windows name (Ill have to modify the registration page to pass these fields in and make them read only, so thats minor).

  • 0
    bbakermmc created

    I was finally able to get it to work, there is something wonky if you put the federation config last. I had to move the external loing and federation configs to be before the cookie auth, then everything works fine.

    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
                app.UseWsFederationAuthentication(CreateWsFederationAuthOptions());
    
                app.UseOAuthBearerAuthentication(AccountController.OAuthBearerOptions);
                
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                    LoginPath = new PathString("/Account/Login")
                });
    
  • 0
    bagy88 created

    Hello :)

    I have one Problem. I managed to get the authentication to ADFS.

    In Startup.cs i have two configurations.

    new ProjectName.Cookie.Configuration().Register(app);

    public void Register(IAppBuilder app)
            {
                app.UseCookieAuthentication(
                   new CookieAuthenticationOptions
                   {
                       AuthenticationType =
                          WsFederationAuthenticationDefaults.AuthenticationType,
                       LoginPath = new PathString("/Account/Login")
                   });
            }
    

    new ProjectName.ADFS.Configuration().Register(app);

    public void Register(IAppBuilder app)
            {
                var audienceRestriction = new AudienceRestriction(AudienceUriMode.Always);
                audienceRestriction.AllowedAudienceUris.Add(new Uri(_realm));
    
                var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();
                issuerRegistry.AddTrustedIssuer(_trustedIssuerThumbprint, _trustedIssuerName);
    
                app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions(WsFederationAuthenticationDefaults.AuthenticationType)
                {
                    Wtrealm = _realm,
                    Configuration = new WsFederationConfiguration() { TokenEndpoint = _wsFederationTokenEndpoint },
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
                    },
                    SecurityTokenHandlers = new System.IdentityModel.Tokens.SecurityTokenHandlerCollection
                        {
                            new SamlSecurityTokenHandlerEx
                            {
                                CertificateValidator = X509CertificateValidator.None,
                                Configuration = new SecurityTokenHandlerConfiguration()
                                {
                                    SaveBootstrapContext = true,
                                    AudienceRestriction = audienceRestriction,
                                    IssuerNameRegistry = issuerRegistry,
                                }
                            }
                        }
                });
    
            }
    

    The User Request a page, he get 302 response to ADFS, log´s in and get back with the session cookie. The Problem is in which step i should create a DB user(save the user in de DB)?

    Another Question: When i make an external Ajax call i get 302 redirect and the ajax call stops in this step, and this is ok. But how to call an ajax call with token to authenticate through the asp net boilerplate app.

    Thank! :)

  • 0
    ismcagdas created
    Support Team

    Hi,

    For the first question, you should create the user in ExternalLoginCallback in AccountController. User must be redirected to this action if any external authantication succeeds. Then you can create the user.

    For the second question, first you need to authanticate and get a token in order to use it for the further requests. Please see this document <a class="postlink" href="https://www.aspnetzero.com/Documents/Development-Guide#token-based-authentication">https://www.aspnetzero.com/Documents/De ... entication</a>.