Single Sign-On with Java Client - java

I am looking for a Single Sign-On authentication in a Java client.
Since I am logged in to Windows using an AD, the main goal is that I do not have to enter username and password again. I want Java to use the Ticket I recieved at Windows-login. This code is the best I have for the purpose:
LoginContext lc = new LoginContext("com.sun.security.jgss.krb5.initiate", new DialogCallbackHandler());
lc.login();
Subject.doAs(lc.getSubject(), (PrivilegedExceptionAction<Void>) () -> {
System.out.println("This is privileged");
return null;
});
I've set the java.security.krb5.conf and java.security.auth.login.config properties with corresponding conf-files, but still a dialog asking for Username and Password pops up.
I also tried working with GSSName, but GSSManager.createCredential() is also asking for Username and Password (probably using the TextCallbackHandler()).
I tried to get along with Waffle, but did not get it working. Most examples and explanations are Server sided (I only found one example combining server and client side, but I was not able to split it up).
I know, there are Similar questions (e.g. this), but i did not get that working without entering a password.
PS: i know, that DialogCallbackHandler is depricated, I use it for test purposes only.

Ok, after several tries I found a solution. The problem was not in the code, but in the registry. As stated on this page, since Java 7 You can't access the ticket of Windows natively. To change this, You have to set an additional registry key. For this, go into the registry folder
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
and add the key
Value Name: AllowTgtSessionKey
Value Type: REG_DWORD
Value: 0x01
To fully make this work you will need some additional settings:
The jaas configuration file
In the jaas configuration file you have to set up which security modules jaas should use. The part in front of the brackets names your configuration. If you use the GSS libraries you must name it com.sun.security.jgss.krb5.initiate. When you use the LoginContext you just pass the name of the configuration as first parameter. My jaas.conf look as follows:
com.sun.security.jgss.krb5.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache = true;
};
The kerberos configuration
You will also need a configuration for the Kerberos module. This mainly contains the realm address, but can hold additional information. A minimal working example:
[realms]
YOUR.REALM.COM = {
kdc = your.realm.com:88
default_domain = REALM.COM
}
Note, that this is case sensitive!
The System Properties
Finally, you have to set up Java to find this files. You do this either by giving the properties on startup or by calling System.setProperty():
System.setProperty("java.security.krb5.conf", "src/resources/krb5.conf");
System.setProperty("java.security.auth.login.config", "src/resources/jaas.conf");

Related

Accessing Keberized Hadoop cluster programmatically

We are trying to access the kerberized Hadoop cluster(Cloudera distribution) using code(java) but getting the below exception.
Caused by: javax.security.auth.login.LoginException: Unable to obtain
password from user at
com.sun.security.auth.module.Krb5LoginModule.promptForPass(Krb5LoginModule.java:897)
at
com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5Login
Module.java:760) at
com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617)
We have used the property "hadoop.security.authentication" as kerberos,fs.defaultFS as hdfs://devha:8020 and passed the keytabfilepath in the userinformationgroup.
First, read the comments on your question. Good stuff.
Taking a step back since that information can be overwhelming there's two possible ways to authenticate to a Hadoop cluster. A user will normally use a username (principal) and password. An application will normally use a principal and a keytab file. A keytab file is created by the Kerberos administrator using the 'kadmin' application.
Furthermore there's the concept of a "Login" user - an application wide default, or a "Current" user that could be specific to your current need. You'll often use the former to access resources on your local cluster and the latter to access resources on an external cluster.
Since I'm using the latter I can give you a quick code snippet to get you started. For initialization:
UserGroupInformation.setConfiguration(configuration);
where "configuration" is either read from the standard location (/etc/hadoop) or generated on the fly. Note - that sets a static value so you need to be very careful!
For the individual user (application) I use
UserGroupApplication user = UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keytabFile);
there are several variants of this method - e.g., do they take username or keytab file? Do they set the "Login" user or do they return a new UserGroupInformation object? Be careful you understand the consequences of which one you're using since some set global values.
You now have to wrap your calls to the cluster in a doAs() call:
user.doAs(new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
// do all of your hadoop calls here
return null;
}
}
I don't recall if you need to do this if you're always using the "Login" user. We need to support both local and external clusters and for us it's easiest to always wrap everything like this. It means we only need to set "user" once, at the start of the action.
See the resources mentioned above if you want details on user impersonation, using SSL encryption (rpc.privacy), etc.

Cannot create Asterisk Stasis App using ari4java library

I am using ari4java library and I have a problem with registering a stasis application.
If I use the command line to connect to Asterisk and listen for events for a specific application name it works. It creates the application and everything is OK. The problem appears when I do it by using the ari4java library in Java. Actually, I'm trying the example from the library's github repository (i.e. - ConnectAndDial.java)[1]. I understand that the ARI.build(...) call:
ari = ARI.build(
ASTERISK_ADDRESS,
"app_test",
ASTERISK_USER,
ASTERISK_PASS,
AriVersion.ARI_3_0_0
);
must create an application named "app_test". The reality is that it does not.
for (Application app : ari.applications().list()) {
System.out.print(app.getName() + " ");
}
The code above, executed after ARI.build(...) prints nothing. That means there is no application registered in Asterisk. Running "ari show apps" in Asterisk CLI also tells me that there is no app registered.
I can't understand, where is the problem? Can somebody, please, help me with this?
Thanks in advance.
P.S.: I am using Asterisk 15.4.0
[1] https://github.com/l3nz/ari4java/blob/master/tests/ch/loway/oss/ari4java/sandbox/sample/ConnectAndDial.java
First of all you need to create an instance of ARI using ARI.build, as you did. For example:
ARI ari = ARI.build(asteriskUrl, "stasisApp", "userid", "secret", AriVersion.ARI_3_0_0);
Besides that you need to define configuration files as follows:
ari.conf - a configuration file that defines user and asterisk properties:
[general]
enabled = yes
pretty = yes
[userid]
type = user
read_only = no
password = secret
extensions.conf - define a dialpan for the application you want to run:
[general]
enabled = yes
pretty = yes
[userid]
type = user
read_only = no
password = secret
http.conf - HTTP server configuration:
[general]
enabled = yes
bindaddr = 0.0.0.0
bindport = 8088
In addition, after creating ARI instance you can open a websocket to listen to ARI events, using: ari.events().eventWebsocket("stasisApp", true, ariCallback);

Connect to the LDAP Active Directory in Java without username and password

I have a simple application written in C#.
That application works on windows machine and user account logged to the Active Directory.
In that application I retrive some information from LDAP Active Directory.
In C# I do connection with LDAP in that way:
DirectoryEntry de = new DirectoryEntry("LDAP://OU=places,DC=system,DC=org");
and next I retrieve needed data (for example):
DirectorySearcher searcher = new DirectorySearcher(de);
searcher.Filter = "(telephone=111222333)";
SearchResultCollection resultCollection = searcher.FindAll();
As you see in that application I do not need log to the LDAP with username and password but only I need to put the correct path:
The constructor of DirectoryEntry looks like that:
public DirectoryEntry(
string path
)
Of course there is a constructor with username and password, but as I said I do not need to use it:
public DirectoryEntry(
string path,
string username,
string password
)
I tried to retrieve the same information in Java and I used the similar code:
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ad.host:389");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "password");
DirContext ldap = new InitialDirContext(env);
and next I retrieve needed data (for example):
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration tel = ldap.search("OU=places,DC=system,DC=org", "(telephone=111222333)", searchControls);
But there is a one difference. As you see I need to put username and password in Java if I want to connect to that LDAP Active Directory.
If I do not put the username and password I will see the following error:
Exception in thread "main" javax.naming.NamingException:[LDAP: error code 1 - 000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1;] remaining name 'OU=places,DC=system,DC=org'
My question is if can I log to the same LDAP Active Directory from the same machine in Java without need to put username and password?
Is there an equivalent to do this in Java like in C# (without put the username and password)?
If using env.put(Context.SECURITY_AUTHENTICATION, "none"); did not work, then your AD environment may not support anonymous authentication, understandably. Anonymous authentication is disabled by default.
When you use new DirectoryEntry(...); in C#, it may seem like you are not using any credentials, but it really uses the credentials of the currently logged on user. So it's borrowing your own credentials to make the call to AD.
Java does not do that. In fact, from the brief Googling I've done just now, it seems like it's quite difficult to make it do that, if that's what you want to do.
There is a question about how to do that here: Query Active Directory in Java using a logged on user on windows
The comment there gives a couple products to look into.
But if you don't want to use any third-party products that may complicate things, you can just provide a username and password.
If you want to test anonymous authentication in C#, you can use something like this:
new DirectoryEntry(ldapPath, null, null, AuthenticationTypes.Anonymous)
I found a walk around solution to create a process and run the powershell script.
In powershell script, you can use the "System.DirectoryServices" to search without passing the username and password.
Please refer Querying Active directory
I have a simple application written in C#. That application works on windows machine and user account logged to the Active Directory.
I guess your C# application simply uses a Windows API which under the hood automagically authenticates with Kerberos ticket granting ticket of your Windows session.
If you want to do that with another programming language you have to do a LDAP SASL bind request with SASL mech GSSAPI. However your e.g. Java-based LDAP client also have to make use of the Windows credentials cache.
See also: Java Platform, Standard Edition Security Developer’s Guide

Error retrieving LDAP info with search

I am trying to setup an LDAP LoginModule (using BrowserLdapLoginModule). The user/password is correctly; it retrieves the roles from the user but when it tries to extract the CN value it cannot find the values.
I have followed the process, and in the end the failure is that I get a javax.naming.NameNotFoundException in the following line
NamingEnumeration roleAnswer = ctx.search(searchBaseDN, roleFilter, roleconstraints);
with the following values (doble quotes not included):
searchBaseDN(String) = "OU=Roles,DC=siafake,DC=aplssib"
roleFilter(String) = "(distinguishedName=CN=Urgencias,OU=Roles,DC=siafake,DC=aplssib)"
derefRoleAttribute(String[] = { "cn" };
With that data, I expect the search to return me Urgencias, yet I only get the exception. It is not a permissions issue, since with the same user/password I can browse the LDAP tree without problem.
Any idea / suggestion? Thanks in advance.
Ok, here is the answer that I found (also, some clarifications to the comments from Terry Gardner comments)
My sysadmins gave me user A ("system" user, that can connect and browse the LDAP). The user that will connect to my application would b user F (final user). When asked about samples to configure my jboss, they redirected my to the BrowserLdapModuleLogin (BLML).
Turns out, BLML works by doing an initial connection with user A, for retrieving user F data (full LDAP "name").
After that, a new connection is setup using user F connection data to validate user/password and retrieve the groups (memberOf attribute) to which it belongs. Until this point, all works as it should (at least with our setup).
The trouble began when I did setup the option to just get the "CN" value (instead of CN=value,OU=organization....). By setting up this option, the module tries again to login as user F into the roles tree to get the attribute. But it happens that F does not have permissions to do so.
As the module was provided by our IT people and I am new to LDAP, I assumed I was just setting up something wrong, and I did not want to change anything in the code. In the end, it happens that in the system that uses it, this module was used only for authentication; the roles were extracted from another DB and I have been forced to code around this issue.
Sorry for the annoyances...

How do I change the port used for livetribe SLP?

I'm attempting to use LiveTribe SLP module (http://livetribe.codehaus.org/LiveTribe-SLP) to provide an SLP service for an application. I want to change the port from 427 to something else entirely. The documentation is sparse and even more confusing is that in the FAQ, it claims to link to an example that would show me exactly what I'm looking for. Unfortunately, it doesn't (unless I'm overlooking something). Does anyone know how to do this?
There is a client and server example here:
http://livetribe.org/SLP-Examples-JMX
(Link broken.)
These are the important lines on the server side:
// Allow this code to be run by non-root users on Linux/Unix
Settings settings = new MapSettings();
settings.put(Keys.PORT_KEY, 4427);
// Create the SLP ServiceAgent that advertises the JMX service
ServiceAgent serviceAgent = SLP.newServiceAgent(settings);
And on the client side:
// Allow this code to be run by non-root users on Linux/Unix
Settings settings = new MapSettings();
settings.put(Keys.PORT_KEY, 4427);
// Create the SLP UserAgentClient that discovers services
UserAgentClient userAgentClient = SLP.newUserAgentClient(settings);
Sorry about the bad documentation. We've had problems with it ever since we changed the L&F of the site to use Twitter Bootstrap.
The page should now fully render:
http://livetribe.org/SLP-Examples-JMX
Link broken.

Categories