Spring Security LDAP: Bind vs. Authenticate against Active Directory in ApacheDS - active-directory

What works
I developed this against our company's AD:
#Bean
public AuthenticationProvider adProvider() {
ActiveDirectoryLdapAuthenticationProvider adProvider = new ActiveDirectoryLdapAuthenticationProvider(
adConfig.getDomain(), adConfig.getUrl(), adConfig.getRootDn());
adProvider.setSearchFilter(adConfig.getSearchFilter());
adProvider.setUseAuthenticationRequestCredentials(true);
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setAuthoritiesMapper(authorities -> List.of(new FooAuthority("*")));
return adProvider;
}
This does work; I can log in using my company credentials. Important: I can use my sAMAccountName (which happens to be my uid as well) to log in.
Goal
Now I want to have some automated tests for certain edge cases, using a local AD. I chose ApacheDS for its cross platform availability, plus it has some Docker containers available. I use openmicroscopy/apacheds
, because it seemed active, documented and configurable, important for a rookie like me.
Problem
The problem is, I cannot log in. I traced it down to two lines in o.s.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider: while searchForUser(ctx, username) in doAuthentication(...) (line 148 in 5.0.12.RELEASE) works with my sAMAccountName (like foobar), contextFactory.createContext(env) in bindAsUser(...) (line 204 in 5.0.12.RELEASE) requires a fully qualified DN (like cn=foobar,ou=people,dc=acme,dc=com) to work.
So it seems there is some misconfiguration on my side, probably because of my misunderstanding... Seems I do need some different user to authenticate than to search afterwards? How do I configure this, and/but why does our company's AD works just fine? PS: I read about anonymous authentication, maybe our company allows such? But using Apache Directory Studio against the company's AD requires me to log in (as far as I can tell)...

LDAP based simple BIND operation always requires the distinguished name (DN) of the entry and password. Only AD allows to perform the BIND operation with samAccountName. AD is somewhat special.

Related

user principal name issues and LDAP

So... this question is maybe not solely a programming question but I hope one of you can shed some light on my issue:
The base need we have in our software is to query the groups a user is associated too with
LDAP. For this task we actually use parts of LDAP Admin to query the user. Actually we want to query for the UserPrincipalName which at least to my knowledge is the most common way right?
So.. our problem is that the AD is setup such that the user has an UPN like foo#HUS
but the user actually is bound to the domain HUS.adomain.com (aka LDAP base: dc=HUS,dc=adomain,dc=com) and searching using an UPN like foo#HUS.adomain.com does not work - only foo#HUS works. So... the question is:
Is this common?
And is there a name/resource for that?
(sorry I'm quite new to that all...)
The goal would be to use as less parameters in the administration tool as possible
aka only the base (and form from the base the UPN username).
Update: I found at least one resource (in German) that states that this is possible but not recommended by Microsoft for Azure AD. (aka having a different mail address than UPN )
When you initiate a LDAP search using a UPN like foo#HUS.adomain.com it wont work because this value is not present in the userPrincipalName value. When you search for a user by building its UPN using all the domain suffix available in the forest, then you would not consider searching the userPrincipalName attribute.
It is very difficult to build every constructed attribute from base for querying because every Active directory environment would be different. As you have mentioned that you would like to build the attribute from base, it may work if this is the only AD infra that you are targeting. Every AD infra would have its own ways in which it will be setup.
However if you would want your tool to work in any AD environment you would have to consider some other parameters.
UPN is a editable attribute . An organization can set it up or can create a user without a UPN value. Below is example of user created programmatically by using old ADSI libraries. You can repro the same by removing any users userprincipalName attribute value and the user logon account name as shown in the pictures below.
UPN is an optional attribute and a user account can be present in AD without it as well. Coming back to your specific environment in this environment only foo#HUS works because "HUS" might be setup as a valid domain suffix within the Active directory. You can check this by opening the domain.msc console on any domain controller or a machine with Remote Server Administration Tools installed. You would find the UPN suffix as shown below . I changed it in my environment as shown below.
The value you will add will now show up in the . If you remove HUS from here for example any existing user who have user#HUS userPrincipalName populated will get removed because this is a optional constructed attribute in AD. And you will have to setup this for all the users in the environment . For example check below after I changed the username to dh # HUS .
The userprincipalName value also got populated with the same.
Hope this helps clarify your query and understand more on how to use the native Active directory tools to understand more while you develop your custom LDAP search functionality/tool.

Get domain\username from microsoft graph

We have an application where we store users login name in the format domain\username. We authenticate via windows and then get additional info from our database by matching the domain\username we get from the user to our database.
Now they want to move to the cloud. We authenticate users via apps in Azure AD. However, the user identifier we get back is first.last#domain.com.
I have fiddled around with https://graph.microsoft.com/v1.0/users/email and the select command to try and get the 'old' name. Howev,er I have not yet found out how to get it.
The reason they move to the cloud is that they are merging two ADs. So some users will be DomainA and some DomainB, but in the same tenant. So my first thought was to try and convert the mail to the other format. However, the two different ADs have different naming standards. One has DOMAINA\fila (two first letters from the first name and two first letters from the last name) and the other one has DOMAINB\firlas. Also it feels really ugly to try and solve it that way.
Is it possible to fetch the users loginname formatted as domain\username via Microsoft Graph?
Using the beta edition of Graph, you can obtain the user's domain and username from the onPremisesDomainName and onPremisesSamAccountName properties:
/beta/users?$select=userPrincipalName,onPremisesDomainName,onPremisesSamAccountName
The domain is stored as a FQDN so you'll need to do some translation. For example, domainName.ad.contoso.com might translate to domainName\).
This will give you a workaround so you can match up users with your internal databases. It is however only a temporary solution. Long-term, you really want to migrate to using the userPrincipalName. This is the primary user identifier and guaranteed to be unique within a given tenant.
Azure AD is a little different than the legacy Active Directory. Certain concepts from legacy AD such as Organizational Units (OUs), Group Policy Objects (GPOs), Kerberos Authentication, Lightweight Directory Access Protocol (LDAP), Domain trusts between multiple domains, and several others simply do not exist in the cloud.

Kerberos/SPNEGO : multiple SPNs for the same AD account

Deploying the same HTTP based application on several web servers (srv1, srv2, etc). Protecting the application with SPNEGO auth. The servers are Linux and AD doesn't know of their existence, i.e. they are not joined to the domain. I've got the whole SPNEGO working smoothly on a single host. Now moving on to the subsequent hosts.
Most guides I've found will tell you that you need
An account in AD
A SPN
A keytab (generated on the AD server and then
moved to the Linux host)
While I believe that (2) + (3) will always need to be per-server, I'm somewhat uncertain about (1). Can I do with only one account? I would really like to not having all these accounts in AD if I can do with only one.
This blog has a good recipe for how it can be done: The first invocation of ktpass (for srv1) should be as described in the all the guides you find on the internet, however subsequent invocations (for srv2, srv3, etc) should be using the -setpass and -setupn options.
However I've found that when one uses the ktpass.exe tool the account's userPrincipalName attribute changes to become as given by princ argument from the last invocation of ktpass. So the name of the srv, e.g. srv3 is coded into the name and the name of the account will therefore basically change with each invocation of ktpass. When the web server performs the final step in the SPNEGO chain of events, which is to contact AD using the keytab as credentials, it will look for an account in AD with a userPrincipalName equal to the SPN and this step will therefore fail. (source, scroll to last post, list item 3). Contradicting this is that I'm using Tomcat and thereby JAAS and as far as I understand I can hardcode the principal name to use in my jaas.conf file thereby effectively ignoring the principal name from the keytab.
Can multiple app servers + single account in AD ever work and if so how?
In short, yes it will work and I will tell you how. First of all let's clarify some things and some statements not properly described in your question or the comments:
You have three machines which serve the same DNS name, this means that you either have a DNS round-robin: service.example.com will returned a shuffled list if IPs or a load-balancer (hard of sort) will only one IP for the A record depending on the load. For Kerberos, both setups are equal in the outcome.
Now, you cannot say that the AD does not know the existence of a service or a server if you require Kerberos authentication. It will and must know otherwise it cannot create service tickets for your clients which they pass on to the server. Additionally, Tomcat will not contact the KDC to accept the security context because the service ticket is encrypted with the account's long-term key.
Here is the approach: You have already figured out that one SPN can be bound to one machine, multiple bindings are not allowed. This is the case when you have the machine name bound to the machine account (srv1$, etc.). You need a service account. The service account is a regular account without password expiration, e.g., my-service#EXAMPLE.COM. For this account, you will bind your CNAME or A record. Have you Tomcat authenticator to accept all securty contexts with this service account and it will work.
How to create this magical service account on a Unix-like OS?
Use mskutil to
create the service account,
create a keytab for that service account,
bind your SPN to that service account and have the keytab updated.
After that you will have a keytab suitable for your use. Verify with an LDAP query (e.g., with Softerra's LDAP browser or else) that the account exists, the SPN (servicePrincipalName) is bound to that account and you are done.
Important: if any of your clients use MIT Kerberos or Heimdal, you must set rdns = false your your krb5.conf.
Godspeed!

SonarQube and LDAP - Case sensitive logins

I am checking SonarQube 5.4 and the latest LDAP plugin 1.5.1. There are however a couple of issues.
First. My AD account is majcicam. If I log in with it, it is correctly shown in the users list. However if I login with MajcicaM (note capital letters) another additional user is added to the list:
As you can see from the attached image. For every login that I do make, seems it is treated as case sensitive and thinks of it as a different user.
Second thing. Once I assign a group to my user, on the next login those settings are gone. Seems that they are not persisted.
Am I doing something wrong? Is this a bug? Are my settings messed up?
Thanks
Mario
No bugs here, just some subtleties about LDAP Plugin configuration and behaviour. :)
Case-insensitive login
Set sonar.authenticator.downcase to true when delegating authentication to an LDAP/AD server which is case-insensitive.
Group mapping behaviour
When group mapping is configured (i.e. you manually configured ldap.group.* or you use the windows authentication mode with lightweight AD config), membership in LDAP/AD will override any membership locally configured in SonarQube. LDAP/AD becomes the one and only place to manage group membership (and the info is fetched each time the user logs in).

Store Active Directory Users in a SQL Database

I need to set a server that creates self-signed certificate when a user register in. So i thought to create a new AD account every time a new users register to the server. BUT, I need to store the user information into a sql server and i can't find a way to do this.
Any idea?
Based on what you describe and your comment:
My problem is that i think that store "public users" (that can register from the web) information into AD is insicure, so i'm trying to find another way to do that "mapping", – Stefano
What you seem to need is an AD domain with a one-way trust:
Your public users are in domain A.
Domain A trusts your internal private domain B.
Your app does AD authentication against domain domain A, and your internal users can authenticate using their full domain credentials (the request gets passed to domain B, which says yay or nay).
Note that this is coming from a guy who hasn't used Windows in a very long time.
I could be giving you terrible advice (and if I am I'm sure one of our Windows folks will clobber me for it).
If you're going to be storing external users for an application, you should be using AD LDS (formerly ADAM) instead of real AD. Or any other generic LDAP, really, but AD LDS is a lot like AD and might fit your needs better.

Resources