I've been tasked with researching/writing an LDAP integration module to support any/all clients that use local LDAP authentication for our new app. As I've never worked with LDAP before, I'm trying to figure out what settings are required/not required, and what settings I'd need to capture from each LDAP system to be able to support them all. So if I'm storing data in a database about each LDAP server, what is needed about that server to be able to successfully auth with a username/password?
I see lots of ou/cn/dc references, but sometimes people don't use them in their connection strings? And unless pre-registered, it seems like I'd have no way of knowing the names of the groups/categories to query against. I was thinking about the SAML spec and was curious if LDAP systems have an endpoint to retrieve some kind of XML describing their LDAP hierarchy? Or if I'd just need to know/ask for it from a sysadmin in advance?
FWIW I'm using Node/ldapjs
There is no standard way of describing the LDAP hierarchy in the manner you were considering. LDAP is in fact self-describing, you can search for a particular entry regardless of it's position in the LDAP tree by looking up one of its attribute's value.
So, to get started with completely unknown LDAP you only require it's network parameters: hostname, port (and even that can be avoided if you consult SRV DNS records (_ldap._tcp.domain.com)) and authentication details in the form of bind DN and password.
After that you can search for users, typically by looking up with filter like (objectClass=inetOrgPerson), or groups of users with filter like (objectClass=groupOfNames). Then you would use common attributes such as username, CN or displayName to reference or display the users in the user interface.
As you can see from this LDAP servers are very self defining and this ideally works for most LDAP servers, but as you perceived in your question it can differ from one LDAP server to another.
So here is my list of LDAP configuration settings that should be configurable:
hostname/port number (if not using DNS discovery)
username/password (if not using anonymous access)
does the server use SSL (port 636 by default) (or detect support for StartTLS)
user filter and user base DN (e.g. (objectClass=inetOrgPerson) and o=users)
group filter and group base DN (e.g. (objectClass=groupOfNames) and o=groups)
Depending on your use case you could define what attributes are used for displaying the user, mapping them to other parts of your application/system or you could determine those from the returned set of attributes. I've seen implementations that have that very configurable and implementations that default to some standard schema.
Related
Hi I'm having issues security my application, enabling authenticated users access to specific endpoints, non-authenticated users access to others and most importantly, continuing to enable the application to communicate with itself, without storing passwords as a String in the case base.
The code base:
My code base consists of numerous packages that communicate via REST and GraphQL calls. With no authentication, this system works fine. Development is in Java 8 with Maven.
Aim:
I am currently in the process of adding authentication to the code base which should enable three things to occur.
The different projects in the application continue to communicate easily.
An "admin" user can log in and make calls either via Swagger or GraphiQL or any methods they require.
The average user will only be able to access specific endpoints such as UI elements (e.g. localhost:8082/user-ui [unique_key])
Current Development:
I've implemented Spring Security In-Memory Authentication (https://www.appsdeveloperblog.com/spring-security-in-memory-authentication/). Which successfully blocks URLs being called and prompts the user for credentials, except on certain predefined endpoints. This fulfilling criteria 3 and part of criteria 2 (as the Admin can access Swagger and GraphiQL).
My Problem:
Unfortunately setting up this system has broken the internal calls as the RestTemplate used to communicate between packages no longer has the correct authentication.
While I could use BasicAuthenticationInterceptor(https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring) to provide the authorization, this would mean having to write the password in a String in the code base. As I understand it, this is bad form as the String is then stored in the String pool. Elsewhere I've managed to avoid this using the CharBuffer before encoding the password, however BasicAuthenticationInterceptorrequires a String.
Any advice on how to proceed would be greatly appreciated.
If you are using basic authentication, you will have to provide the password when you are making internal calls with resttemplate. That doesn't mean you need to store the sensitive data (in this case credentials for your basic authentication) in plain text in the code base. One of the most common practices is to use an external file to store the sensitive data and then get the application to use them at run time. You may also want to ignore that file from git repository to prevent that being part of the code base.
If you are using Spring boot have a look at the environment specific properties files, which could be an ideal way to store profile specific configuration and data like these.
https://docs.spring.io/spring-boot/docs/1.5.5.RELEASE/reference/html/boot-features-external-config.html
https://www.baeldung.com/properties-with-spring
If you are worried about storing the credentials in plain text in properties file, you can also encrypt sensitive data in your properties files.
Spring Boot how to hide passwords in properties file
I have a problem about something I've never really encountered before, that is connecting to an LDAP from a NodeJS application. Until now, I didn't even know there was such a thing as an LDAP, so I've been learning on the go. That's why this may be a stupid question, but I haven't found any concise answer.
The requirement is: "log to an LDAP from your application with the user and pass provided in your login screen". The client has an LDAP, and wants to use it to authenticate our application's users, so the user and pass entered in our log in screen are used to try to log in to the LDAP.
I understand that I need three things to connect to an LDAP:
the server's URL
A user (with pass)
And a DN to bind to
I'm currently using ldapjs to connect from NodeJS. The operation that I'd need to use to authenticate the user, I understand, it's the bind operation. For that, I need to have created the server (already done, and no problems) and pass the dn, and the password. I assume the DN includes the user. Something like
CN=myuser,OU=MyOrg,OU=Users,DN=MyLdapServer,DN=com
Which works... provided that the users belong to the same "branch". That is, if all of them are in, say, OU=MyOrg. That's why I'm able to "hardcode" the DN in the bind() and just change the user with a replace.
Problem is, not all of them belong to the same "branch" (I don't know the technical name for this). Say, I have some in OU=MyOrg, some in OU=MyOtherOrg...
So I don't know to begin with what the user's organization is, so I can't make him bind to the LDAP client because I lack the DN.
The client only provided us with an example, from another application that used ASP.NET and ADO.NET to do so, using something like a SQL command to get the LDAP info. Thing is, the equivalent to the DN was a more generic one. Something like
ldap://MyLdapServer.com/CN=[the_user_provided]
This, apparently, worked. If I try to do the same thing, using that more "general" DN route (which, I assume, is a node higher on the LDAP tree), providing one of the users' password, I get an authentication error.
So, how come? What am I missing? What do I need to log the users to LDAP using just the "CN=[username]" DN? Is that something that only ADO.NET can use?
Thanks, and sorry if it's too generic a question.
Per the comment I made:
To bind with Active Directory you do not need to know the full DN of the user. There is a list of all the different available methods on this page in the docs. So you could use user#domain.com as an example. Or just the supplied username would work in most cases.
The question may sound odd, but I have a worst case scenario.
My application server is on http://10.10.10.10/app (say it app-server) and http-apache server is on http://some.dns.com/app (say it http-server). Both are different system-server.
I know app-server shouldn't directly accessible publically, but let's assume it is publically accessible. Now Shibboleth is installed on http-server , securing path http://some.dns.com/app/secure . While one servlet is mapped to get attributes from path /secure.
If someone manages to create fake http-apache-server (say fake-http-server) and that too points to app-server. So here fake-http-server can directly have access to /secure path and that server can manually send shibboleth-like attributes and can login in system without protection.
My question here is, Is there a mechanism in Shibboleth where I can check the shibboleth session in my application - not only in http layer.
The mod_shib Apache module sets environment variables by default. These variables cannot be spoofed by a proxying Apache server.
From the docs:
The safest mechanism, and the default for servers that allow for it,
is the use of environment variables. The term is somewhat generic
because environment variables don't necessarily always imply the
actual process environment in the traditional sense, since there's
often no separate process. It really refers to a set of controlled
data elements that the web server supplies to applications and that
cannot be manipulated in any way from outside the web server.
Specifically, the client has no say in them.
If you don't trust the Apache webserver, you can parse the SAML assertion in your code and validate the signatures in the assertion using the certificate provided by the Identity Provider (IdP) making the SAML assertion. But checking signatures is difficult and you need to deal with cases like key rotation and how to handle new certificates being used by the IdP. Shibboleth handles these very difficult and important tasks for you.
I am using TACACS+ to authenticate Linux users using pam_tacplus.so PAM module and it works without issues.
I have modified the pam_tacplus module to meet some of my custom requirements.
I know by default, TACACS+ does not have any means to support linux groups or access level control over linux bash commands, however, I was wondering is there any way that some information could be passed from TACACS+ server side to let the pam_tacplus.so module which can be used to allow/deny , or modify the user group on the fly [from pam module itself].
Example: If I could pass the priv-lvl number from server to the client and which could be used for some decision making at the PAM module.
PS: I would prefer a method which involved no modification at the server side [code], all modification should be done at Linux side ie pam_tacplus module.
Thanks for any help.
Eventually I got it working.
Issue 1:
The issue I faced was there is very few documentation available to configure TACACS+ server for a non CISCO device.
Issue 2:
The tac_plus version that I am using
tac_plus -v
tac_plus version F4.0.4.28
does not seem to support
service = shell protocol = ssh
option in tac_plus.conf file.
So eventually I used
service = system {
default attribute = permit
priv-lvl = 15
}
On the client side (pam_tacplus.so),
I sent the AVP service=system at authorization phase(pam_acct_mgmt), which forced the service to return priv-lvl defined at the configuration file, which I used to device privilege level of the user.
NOTE: In some documentations it is mentioned that service=system is not used anymore. So this option may not work with CISCO devices.
HTH
Depending on how you intend to implement this, PAM may be insufficient to meet your needs. The privilege level from TACACS+ isn't part of the 'authentication' step, but rather the 'authorization' step. If you're using pam_tacplus, then that authorization takes place as part of the 'account' (aka pam_acct_mgmt) step in PAM. Unfortunately, however, *nix systems don't give you a lot of ability to do fine grained control here -- you might be able to reject access based on invalid 'service', 'protocol', or even particulars such as 'host', or 'tty', but probably not much beyond that. (priv_lvl is part of the request, not response, and pam_tacplus always sends '0'.)
If you want to vary privileges on a *nix system, you probably want to work within that environments capabilities. My suggestion would be to grouping as a means of producing a sort of 'role-based' access controls. If you want these to exist on the TACACS+ server, then you'll want to introduce custom AVP that are meaningful, and then associate those with the user.
You'll likely need an NSS (name service switch) module to accomplish this -- by the time you get to PAM, OpenSSH, for example, will have already determined that your user is "bogus" and send along a similarly bogus password to the server. With an NSS module you can populate 'passwd' records for your users based on AVPs from the TACACS+ server. More details on NSS can be found in glibc's documentation for "Name Service Switch".
HornetQs default SecurityManager (HornetQSecurityManagerImpl) will check users/roles that are stored in the hornetq-users.xml. I want use LDAP for authenticating users; I have two ways:
Using Jass, and use it with LDAP for authenticating users.
Implementing SecurityManager interface manualy, and using LDAP in my own security manager implementation.
Which one is better? Other approaches? What should i do? (experience, sample)
I'd say it's always better to use something that's ready and tested. Using JAAS with Ldap will give you an easier path as that should work nicely.
On the hornetq's distribution there's an example showing how to configure JAAS. You can just get the distribution zip at http://www.jboss.org/hornetq/downloads.html and refer the the examples that are part of hornetq already.