I am trying to secure Confluent Control Center 7.2.2 with the jetty LdapLoginModule. I have the following jaas configuration working.
c3 {
org.eclipse.jetty.jaas.spi.LdapLoginModule required
useLdaps="true"
contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
hostname="ldaps.xxxx.xxxxx"
port="xxx"
bindDn=<user principal name>
bindPassword=<user password>
authenticationMethod="simple"
forceBindingLogin="true"
userBaseDn="DC=xxxx,DC=xxxx,DC=xxx,DC=xx"
userRdnAttribute="userPrincipalName"
userIdAttribute="userPrincipalName"
userObjectClass="user"
roleBaseDn="OU=xxxxxx,OU=xxx,OU=xxxxx,DC=xxxx,DC=xxxx,DC=xxx,DC=xx"
roleNameAttribute="cn"
roleMemberAttribute="member"
roleObjectClass="group";
};
I would like to avoid passing a bindDn and bindPassword and use the authenticating user credentials to bind instead. My understanding is that forceBindingLogin set to true should make that possible.
forceBindingLogin
Indicate whether to bind as the user that is authenticating (true), otherwise bind as the manager and perform a search to verify user password (false).
Although when I remove bindDn and bindPassword from my config I get the following error:
DAP: error code 1 - 000004DC: LdapErr: DSID-0C090A71, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v3839
It looks like bindDn is still used when forceBindingLogin is set to true.
I noticed that in the Confluence documentation, the bindDn config went from optional to required between 6.1.9 and 6.2.0. Jetty was upgraded to 9.4.39, but there is no mention as to why bindDn would now be required.
I don't have experience with Confluent Control Center, but have been dealing with a lot of Java applications and OAuth that uses LDAP authentication during the years. As a DevOps I had to also manage a few LDAP instances myself so I will be rather speaking from that background.
The authentication process with OpenLDAP requires one of the following to be true:
Allows anonymous (connection) binding
This configuration allows you to connect to the LDAP server as an anonymous user and lookup any object in the tree and therefore find any groups, users, etc.
Manager/User dn (connection) binding
This configuration mandates you to connect to the LDAP server as a pre-configured user that has access to lookup objects in the tree and find the requested groups,users,etc. You can have many Manager DNs configured to access different parts of the LDAP tree.
Notice I mentioned CONNECTION binding - think of this as how you would connect to Postgres or MySQL. You need to have some credentials in order to lookup tables or if anonymous is enabled you can do pretty much anything.
The same thing applies to LDAP servers -- anonymous binding will allow you to establish a connection and lookup anything and manager / user dn requires authentication before the connection can be established.
People are not always deeply aware of LDAP's architecture and the documentation doesn't really help there. As such, the terminology makes you jump to the rational conclusion you jumped to:
#alex: I would like to avoid passing a bindDn and bindPassword and use the authenticating user credentials to bind instead
This would work only when the LDAP server is configured to allow Anonymous connections. If it is configured to require Manager/User DN connection:
When you bind as the user the authentication will likely pass (unless LDAP is configured not to allow that at all).
Once it succeeds it you would attempt to lookup the authorization objects (roles / groups / etc). At this point it will fail due to the inability to do the needed lookups and finally the result will be failed login.
To validate if this is the case you are ending in you should:
Use some tool to the LDAP server (you can try Apache Directory Studio
Setup a connection with binds as the bespoken user (i.e. my-username; not the manager dn, not a read-only dn)
Once you are connected try to lookup the userBaseDn and roleBaseDn DN's -- you are most likely not going to see any of the roles.
If the above is true then what you want is not possible with the current LDAP server setup.
If not -- then the LDAP server truly allows you to bind as the user and to lookup the directory tree. In this case you should open up a bug report with Confluent.
Related
I have a NIFI image running in openshift and a postgres in the cloud "owned" by another department.
They sent to us a certificate(".crt") and a key(".key"), since the log-in is made trough client certificate, instead of username and password. I have succeeded to log-in in pgAdmin 4, but not to connect the NIFI to the Postgres with certificate and key.
I have uploaded the certificate and the key to the image (using a secret and mounting it) so if I go to the pod terminal I can access it.
But, when I pass to a DBCPConnectionPoll service the connection string bellow and activates an ExecuteSQL processor, I receive an exception that the certificate is not valid, as follows:
ERROR
ExecuteSQL[id=...] Unable to execute SQL query <...>;
due to java.sql.SQLException: Cannot create a PoolableConnectionFactory (FATAL: connection requires a valid client certificate).
No FlowFile to route to failure: org.apache.nifi.processor.exception.ProcessException: java.sql.SQLException: Cannot create a PoolableConnectionFactory (FATAL: connection requires a valid client certificate)
I have tried to pass the certificate in two ways to the DBCPConnectionPoll service:
1) as parameters in the connection string ("database connection url" property:
jdbc:postgresql://<ip>:<port>/<username>?user=<username>&sslTrue&sslcert=/etc/.../mycerts/mycert.der&sslkey=/etc/.../mycerts/mykey.key.pk8
2) adding properties in the service (+ button and the just parameter name and the path as the value) and just passing this as url:
jdbc:postgresql://<ip>:<port>/<username>
Both seems to work generally speaking, since I can connect to another postgres I have which not requires ssl certification.
Some considerations:
1) My assumption here is that the connection string in the NIFI does not know to read properly the file path for the certificate and key.
2) I have converted the certificates a bunch of times to different types that java can receive in order to see if that was the problem, but I still receive the same exception. So it seems that the connection pool just does not "achieve" the files at all. Nevertheless, if some one has a say in this topic, it can be handy, after the main problem is solved. So appreciate some tips here as well.
3) I have also read the NIFI source code and it seems that NIFI uses normally JDBC classes to create the connection pool, so a connection string as I passed would have worked in java code, but somehow doesn't work in NIFI (which is written in java).
4) The jdbc driver and everything else is configured properly, since I can work with a non-secure postgres in NIFI.
Thank you very much.
A co-worker found the 'simple solution' to the problem I asked and I would like to share so it can help others.
What was missing was the property sslmode = require. After including that, the service worked perfectly. Actually, I am not sure why it didn't work with sslmode = prefer, since it is what my pgadmin is using for the same database and there it works perfectly. It seems like we must 'force' nifi to use ssl in this case - see documentation here: https://jdbc.postgresql.org/documentation/head/ssl-client.html.
Moreover, some insights:
It worked with certificate in '.der' and key in '.pk8' formats (didn't have to use trust-store and key-store as needed in other services).
One can add in the 'plus' button the properties and give them the right name as we would do in java code, instead of concatenating every property in the connection string (see second option in the question above).
Make it helps others as well.
I need some help delegating user authentication in my spring-based application to Active Directory that seems to be delegating this responsibility to Kerberos - I can't seem to figure out how to do this. Here is more of what the mess really looks like:
I followed Spring guide on configuring Spring Security to work with an LDAP server. It went fine.
I got host, port of my actual LDAP server. I configure Spring Security to talk to it, it won't allow me to authenticate.
OK, I download jxplorer and connect to my LDAP server with it successfully. If jxplorer can connect to LDAP only knowing HOST, PORT, USERNAME, and PASSWORD, I figure my application should be able to do the same.
Weirdly, my LDAP does not show an OU=people. My people are scattered deeper in the tree among various OUs, an OU per department kind of way - but, most people are found equally deep inside the tree.
Also WEIRDLY, my actual people nodes that uniquely identify a person have no userPassword attribute.
For experimentation, I configure Spring Security in such a way that it tries to authenticate an individual by looking in the OU that represents my department and tell it to use as password mailNickname (using PlaintTextPasswordEncoder()) and it works fine - only on port 3268, not on 389.
At this point I start speculating - LDAP, is telling my spring-based app that it needs to talk to Kerberos, and I did not tell it how to do that, so that explains why my app fails to authenticate. BUT, no one told jxplorer that Kerberos will authenticate it and yet it managed to get a view of the LDAP tree. Clearly, my spring-app's assumptions != jxplorer's assumptions. I give them the exact same info yet one manages to authenticate the other not. Anyone any idea?
EDIT:
ok, so, I still do not have this solved, but my error has changed and that is a mark of progress, I suppose.
I configured spring according to this: link
Now, when I try to log in, if I give a wrong password or username, I get the complaint that clearly indicates that password is given wrong. However, if I give the correct password, the complaint differs.
The end of stack trace includes:
Caused by: javax.security.auth.login.LoginException: Pre-authentication information was invalid (24)
But, the debug also indicates that the user is found in kerberos database because it says: "principal is username#correct_realm" and "Added server's keyKerberos Principal correct_user#correct_realm" and does some hex dump.
Because of that, I am sure that my keytab is not doing its job. I am certain that my key tab is found by Spring because it says: KeyTab is my_keytab_file (otherwise it'd say: KeyTab is null).
If it is configured with Kerberos, you can try SPNEGO. It's one of the best libraries around for Kerberos in Java.
READ: http://spnego.sourceforge.net/
Sample code for Kerberos Auth:
Example usage (username/password):
public static void main(final String[] args) throws Exception {
System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("java.security.auth.login.config", "login.conf");
SpnegoHttpURLConnection spnego = null;
try {
spnego = new SpnegoHttpURLConnection("spnego-client", "dfelix", "myp#s5");
spnego.connect(new URL("http://medusa:8080/index.jsp"));
System.out.println(spnego.getResponseCode());
} finally {
if (null != spnego) {
spnego.disconnect();
}
}
}
I use the Jinterop library for an access to remote WMI.
JISystem.setAutoRegisteration(true);
JISession session = JISession.createSession(System.getenv("USERDOMAIN"), login, password);
session.useSessionSecurity(true);
final JIComServer server = new JIComServer(JIProgId.valueOf(WBEM_PROGID), HOST, session);
I want to use impersonation for accessing with current user and password to remote machine. But when I use empty login and password, I always get exception
jcifs.smb.SmbAuthException: Logon failure: unknown user name or bad password.
at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:546)
Is this possible to use impersonation in Jinterop?
I am not 100% sure, but I have worked with j-interop for some time and I have never seen or read about this feature, so I don't think that this is possible. In my opinion you always have to specify the credentials.
Further, I am curious if this is really working for you?:
JISystem.setAutoRegisteration(true);
This means that j-interop will automatically try to modify values/keys in the registry as needed. In my experience, in case you want to access the WbemScripting.SWbemLocator class, due to tighter security constraints (the necessary keys are owned by the 'TrustedInstaller' user) this automatic modification is not possible any more starting from Windows Vista and above. I always had to set this to false and modify the values/keys manually in the registry.
I've installed the Websphere MQ 7.5 and written a Java-client to connect to the queue. To perform the task, I'ev created a custom connect-to-server channel that is based on the SYSTEM.DEF.SVRCONN channel.
Firstly, to block all users with administrator privileges and all anauthorized users for all channels I've types such a command (runmqsc TEST_MANAGER): SET CHLAUTH(*) TYPE(BLOCKUSER) USERLIST('nobody', *MQADMIN) . Now I see this restriction in the MQ Explorer (TEST_MANAGER -> Channels -> Channel Identification Records).
After that, to provide my test user (Java-client) with an access, I've typed such a command:
SET CHLAUTH(TEST_CHANNEL) TYPE(ADDRESSMAP) ADDRESS('*') MCAUSER('TestUser') .
Lastly, I've set the username/password pair in the Spring's UserCredentialsConnectionFactoryAdapter where the username is TestUser.
The problem is I can't connect with the 2035 MQRC_NOT_AUTHORIZED exception. If I remove the 'nobody'/*MQADMIN blocking rule, everything works fine (only the rule for the TestUser client rule presents).
SET CHLAUTH(TEST_CHANNEL) TYPE(ADDRESSMAP) ADDRESS('*')
MCAUSER('TestUser')
I do not think you understand this command. This command says that ALL applications connecting on channel 'TEST_CHANNEL' will use UserID of 'TestUser'.
I've set the username/password pair in the Spring's
UserCredentialsConnectionFactoryAdapter where the username is
TestUser.
Setting a Password is pointless, as MQ does NOT perform authentication. You need to purchase a 3rd party product (i.e. MQAUSX) to handle the authentication. Also, your CHLAUTH command is actually overriding whatever UserID you set in your Spring application.
The problem is I can't connect with the 2035 MQRC_NOT_AUTHORIZED exception. If I remove the 'nobody'/*MQADMIN blocking rule, everything works fine (only the rule for the TestUser client rule presents).
Did you use the setmqaut command to give the UserID 'TestUser' the appropriate access to the queue manager and queue?
Turn on the queue manager's Authority Event and to see exactly why MQ is returning 2035.
i'm trying to make an application with the Keberos protocol and the GSS-API in Java, and i've already made the authentication and the context establishement before calling the doAsPrivileged method.
In this method I get the mutual authentication sending a simple token from the client to the server, but after that i want to make some other things.
I want to open a new window with a table of products to let the client select them and buy something and that was connected to a database in the server.
my question is about how can a i use this context in other frames that are diferent from the original doAsPrivileged action class.
i get an error GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt) and i don't know how can i find this TGT to send it more than one time to the server.
thank you.
I ran into a similar issue as well.
Your code fails because Java tries to use GSSAPI with the default login config name. Which is com.sun.security.jgss.initiate. To perform a GSS call for someone else or with another login conf name you have to use the LoginContext, obtain the subject and then do a doAs. As far as I can see, every action involving ticket exchange has to be done in a PrivilegedAction if you don't stick to the defaults. That's why our stuff's failing :-(