bastillion-io / Bastillion

Bastillion is a web-based SSH console that centrally manages administrative access to systems. Web-based administration is combined with management and distribution of user's public SSH keys.
https://www.bastillion.io
Other
3.19k stars 382 forks source link

Documentation on Active Directory profile binding #323

Open ThinkBriK opened 5 years ago

ThinkBriK commented 5 years ago

Hi !

277 suggest that you can mange to connect to Active Directory and map profiles to groups using ldap-ol-with-roles. Could you provide additionnal information or update the documentation ?

Is it working at all ? Thank you !

ThinkBriK commented 5 years ago

I'm using the following jaas config :

    org.eclipse.jetty.jaas.spi.LdapLoginModule required
    debug="true"
    useLdaps="true"
    contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
    hostname="myad.mydomain.com"
    port="636"
    bindDn="CN=bastion,CN=Users,dc=mydomain,dc=com"
    bindPassword="mybastionpassword"
    authenticationMethod="simple"
    forceBindingLogin="true"
    userBaseDn="cn=users,dc=mydomain,dc=com"
    userRdnAttribute="sAMAccountName"
    userIdAttribute="sAMAccountName"
    userPasswordAttribute="unicodePwd"
    userObjectClass="user"
    roleBaseDn="cn=roles,dc=mydomain,dc=com"
    userRoleName="memberOf"
    roleNameAttribute="sAMAccountName"
    roleMemberAttribute="member"
    roleSearch="(member={0})"
    roleObjectClass="group";
};

and I'm stuck on the exact step as #277 , I've got a null pointer exception when trying the user bind :

2019-09-26 14:55:20.810:INFO:oejjs.LdapLoginModule:qtp1501587365-15: Attempting authentication: CN=John Doe,CN=Users,DC=mydomain,DC=com
2019-09-26 14:55:21,316 ERROR ExternalAuthUtil - java.lang.NullPointerException
java.lang.NullPointerException: null
        at io.bastillion.manage.util.ExternalAuthUtil.login(ExternalAuthUtil.java:160) [classes/:?]
        at io.bastillion.manage.db.AuthDB.login(AuthDB.java:62) [classes/:?]
        at io.bastillion.manage.control.LoginKtrl.loginSubmit(LoginKtrl.java:73) [classes/:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?

The problem is still the userInfo.fetchRoles() method that returns a null pointer exception.

ThinkBriK commented 5 years ago

If it could work any AD deployment could map dynamically users to profiles (and profiles to machines if using bastillion-ec2). It's a very important feature !

skavanagh commented 5 years ago

Do you know what version of Bastillion you are on? The stack trace doesn't seem to line up with the latest.

ThinkBriK commented 5 years ago

Hi, you're right it's the previous version (bastillion-v3.05_01) running in AWS using your AMI

ThinkBriK commented 5 years ago

I'll update and retest !

skavanagh commented 5 years ago

3.05_01 should have the fix from #277

I think these maybe wrong

userRoleName="memberOf"
 roleSearch="(member={0})"

According to the docs there is no userRoleName or roleSearch. Valid attributes should be here..

https://www.eclipse.org/jetty/javadoc/9.4.6.v20170531/org/eclipse/jetty/jaas/spi/LdapLoginModule.html

ThinkBriK commented 5 years ago

I upgraded to the last version and used the same configuration with the 2 options removed and I still have the same Null Pointer execption

2019-09-27 16:12:56,260 ERROR ExternalAuthUtil - java.lang.NullPointerException
java.lang.NullPointerException: null
        at io.bastillion.manage.util.ExternalAuthUtil.login(ExternalAuthUtil.java:160) [classes/:?]
        at io.bastillion.manage.db.AuthDB.login(AuthDB.java:68) [classes/:?]
        at io.bastillion.manage.control.LoginKtrl.loginSubmit(LoginKtrl.java:74) [classes/:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
        at loophole.mvc.base.BaseKontroller.execute(BaseKontroller.java:171) [lmvc-1.04.00.jar:?]
        at loophole.mvc.base.DispatcherServlet.execute(DispatcherServlet.java:75) [lmvc-1.04.00.jar:?]
        at loophole.mvc.base.DispatcherServlet.doPost(DispatcherServlet.java:57) [lmvc-1.04.00.jar:?]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) [servlet-api-3.1.jar:3.1.0]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [servlet-api-3.1.jar:3.1.0]
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:852) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1604) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:226) [websocket-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1591) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at loophole.mvc.filter.SecurityFilter.doFilter(SecurityFilter.java:96) [lmvc-1.04.00.jar:?]
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1591) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at loophole.mvc.filter.CSRFFilter.doFilter(CSRFFilter.java:75) [lmvc-1.04.00.jar:?]
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1583) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:536) [jetty-security-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1581) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1307) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:482) [jetty-servlet-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1549) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1204) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:221) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.Server.handle(Server.java:494) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:374) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:268) [jetty-server-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:426) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:320) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:158) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [jetty-io-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:135) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) [jetty-util-9.4.20.v20190813.jar:9.4.20.v20190813]
        at java.lang.Thread.run(Thread.java:834) [?:?]
skavanagh commented 5 years ago

Hard for me to tell how your AD is setup. but

roleNameAttribute="sAMAccountName"

doesn't look right to me.. should it be

roleNameAttribute="cn"

ThinkBriK commented 5 years ago

Actually in AD both attributes coexist, I'll give it a shot

ThinkBriK commented 5 years ago

No luck, it doesn't work either. Actually I already validated the requests using ldapsearch to be sur I wasn't messgin something up.

ThinkBriK commented 5 years ago

To be exact the following ldapsearch command works :

ldapsearch -H ldaps://myad.mydomain.com:636 -x -W -D "CN=bastion,CN=Users,dc=mydomain,dc=com" -b "cn=roles,dc=mydomain,dc=com" "(ObjectClass=group)" "member"
# TEST Group, Users, mydomain.com
dn: CN=TEST Group,CN=roles,DC=mydomain,DC=com
member: CN=TEST-user,CN=roles,DC=mydomain,DC=com
member: CN=TEST-user2,CN=roles,DC=mydomain,DC=com
# search result
search: 2
result: 0 Success
skavanagh commented 5 years ago

What are your JAAS module attributes again? I think for your roles it should be something like..

roleBaseDn="CN=roles,DC=mydomain,DC=com"
roleNameAttribute="CN"
roleMemberAttribute="member"
roleObjectClass="Group";
ThinkBriK commented 5 years ago

That's my actual configuration, it's still not working ... Any lead on how to get more traces of what is going on ?

skavanagh commented 5 years ago

set this line https://github.com/bastillion-io/Bastillion/blob/master/src/main/resources/log4j2.xml#L30 to debug and also make sure you have debug set to true in the jaas.conf https://github.com/bastillion-io/Bastillion/blob/master/src/main/resources/jaas.conf#L31

ThinkBriK commented 5 years ago

I'll try this today !

ThinkBriK commented 5 years ago

OK i didn't try ... I had no time to do this, I will try probably next week as I should have a lower work load.

ledufakademy commented 4 years ago

i have the same issue , is possible to have a config file for Active Directory ?

With forceBindDn=true 2020-04-25 15:22:13,541 DEBUG BaseKontroller - Setting auth.password : xxxxxxxx 2020-04-25 15:22:13,541 DEBUG BaseKontroller - Setting auth.password : xxxxxxxx 2020-04-25 15:22:13,542 DEBUG BaseKontroller - Setting auth.otpToken : 2020-04-25 15:22:13,542 DEBUG BaseKontroller - Setting auth.otpToken : 2020-04-25 15:22:13,542 DEBUG BaseKontroller - Setting auth.username : myusername 2020-04-25 15:22:13,542 DEBUG BaseKontroller - Setting auth.username : myusername 2020-04-25 15:22:13.556:INFO:oejjs.LdapLoginModule:qtp1268066861-14: Attempting authentication: CN=myusername,OU=Linux,DC=domain,DC=local 2020-04-25 15:22:13,581 ERROR ExternalAuthUtil - java.lang.NullPointerException java.lang.NullPointerException: null 2020-04-25 15:37:11,967 INFO LoginAudit - myusername(192.168.50.13) - Authentication Failed : Login credentials are invalid 2020-04-25 15:37:11,968 DEBUG DispatcherServlet - forward: /login.html

or with false 2020-04-25 15:32:49,754 DEBUG ExternalAuthUtil - javax.security.auth.login.LoginException: Echec de connexion : tous les modules ont été ignorés javax.security.auth.login.LoginException: Echec de connexion : tous les modules ont été ignorés

Debian 10 buster, jdk 11, last release of Bastillion.

Note : with jaasModule=ldap-ad , it's fine (despite first login , claim profiles not associated with user ... )

whbogado commented 4 years ago

I found out that this is related to how the LdapLoginModule class handles the user info when authentication is done via LDAP bind. From org.eclipse.jetty.jaas.spi.LdapLoginModule:

@Override
public UserInfo getUserInfo(String username) throws Exception
{
    Attributes attributes = getUserAttributes(username);
    String pwdCredential = getUserCredentials(attributes);

    if (pwdCredential == null)
    {
        return null;
    }

    pwdCredential = convertCredentialLdapToJetty(pwdCredential);
    Credential credential = Credential.getCredential(pwdCredential);
    return new LDAPUserInfo(username, credential, attributes);
}

When there is no userPassword attribute in the LDAP entry getUserInfo() returns null. This occurs when forceBindingLogin="true". Since it is common to LDAP to not return the userPassword, I see no easy workarround.

As can be seen from the login() method, the LdapLoginModule does not even try to get the user info when forceBindingLogin="true":

if (_forceBindingLogin)
{
    authed = bindingLogin(webUserName, webCredential);
}
else
{
    // This sets read and the credential
    UserInfo userInfo = getUserInfo(webUserName);
    ...
}

The NPE is caused at this point in ExternalAuthUtil because userInfo is null:

UserInfo userInfo = loginModule.getUserInfo(auth.getUsername());

//fetch assigned roles
userInfo.fetchRoles();

The solution would be to extend org.eclipse.jetty.jaas.spi.LdapLoginModule to override getUserInfo() which also would have other benefits like avoiding using reflection to get the JAAS configuration parameters.