2

I know it must be a very easy question, but I am new to java and find it hard to get exact code that I need. What I need to be able to do is to get currently logged in username from Windows and check whether this user belongs to the specific AD user group which needs to be defined in some config file. It is very easy to do in C#, but I have no idea how to do it in JAVA. Sample code would be great. In c# I would put security group into App.Config into app settings then I can grab Windows Identity of the currently logged in user and then iterate through all the groups user belongs to and match with desired. I need to do exactly the same in java

fenix2222
  • 4,602
  • 4
  • 33
  • 56
  • "I find it hard to get exact code that I need." Unfortunately, that is no coincidence at all: Java's integration with the Windows development platform is no match to C#'s level of integration. The last time I needed to do something like that I had to jump through all sorts of hoops with Open LDAP (including debugging a concurrency issue in Novell's code). – Sergey Kalinichenko Jun 12 '12 at 23:34

3 Answers3

3

If you only care about the currently logged on Windows user (i.e., your Java program will be running on Windows) and don't mind using JNA, you can use the function supplied in platform.jar, Advapi32Util#getCurrentUserGroups() to get the groups that a user is a member of.

For example:

import com.sun.jna.platform.win32.Advapi32Util;

for (Advapi32Util.Account account : Advapi32Util.getCurrentUserGroups()) {
    System.out.println(account.fqn);
}

This also takes advantage of the fact that Windows caches the users membership in all groups (including groups containing other groups the user is a member of) when the user logs on.


The requirements here seem kind of non-specific and this is starting to veer into areas that are probably not a great fit for SO, but I'll give it a go anyway.

Ultimately, where your system is going to be run determines how difficult the setup is going to be. If you are going to be running on a Windows-based server connected to the same domain you are authenticating with, then you should look at Waffle, which provides a servlet, a Spring Security filter, a JAAS plugin and a few other ways that you can implement Windows Integrated Authentication which uses native Windows methods to load the Windows identity and associated Active Directory groups. This will provide you with the experience most similar to using IIS and WIA with a .NET framework application. The down-side to this is that the server needs to be run on a Windows system.

Unfortunately, running in a non-Windows environment is going to require more setup and configuration. The most integrated solution is likely Spring Security which has a Kerberos extension capable of providing SPNEGO (Windows Integrated Authentication). The link above has the details (I believe they are still current) on what is necessary to get the Kerberos filter up and running. To access the group information, you would need to change the userDetailsService value in the example security.xml file. The easiest thing to do here would be to provide an appropriately configured LdapUserDetailsService as the object here. I'm not all that experienced with Spring, but it looks like the configuration would be something like (this is missing the contextSource).

<bean id="adUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg value="dc=domain,dc=com"/>
    <constructor-arg value="(sAMAccountName={0})"/>
    <constructor-arg ref="contextSource" />
</bean>

<bean id="adAuthoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
    <constructor-arg ref="contextSource"/>
    <constructor-arg value="dc=domain,dc=com" />
    <property name="groupSearchFilter" value="(member={0})"/>
    <property name="rolePrefix" value="ROLE_"/>
    <property name="searchSubtree" value="true"/>
    <property name="convertToUpperCase" value="true"/>
</bean>

<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
    <constructor-arg ref="adUserSearch"/>
    <constructor-arg ref="adAuthoritiesPopulator"/>
</bean>

This should get you a Kerberos authenticated user with their associated groups.

If Spring Security isn't acceptable, you could try rolling your own version of this using perhaps Shiro and the pure-Java SPNEGO filter, but showing an example of that would require basically writing a program.

I hope this helps. Once you've decided on an approach, it's probably appropriate to address more specific questions as SO-type questions.

ig0774
  • 39,669
  • 3
  • 55
  • 57
  • Thank you so much. I will try it out. This com.sun.jna.platform.win32.Advapi32Util package, is it included already in Java standard installation or do I have to install it somehow. I am new with java so have no idea. – fenix2222 Jun 13 '12 at 21:51
  • 1
    Also, how is it going to behave on non-windows machines? – fenix2222 Jun 13 '12 at 21:59
  • @fenix2222: It's not included in the standard Java package. It's part of JNA (which I linked to above). This will not work at all on non-Windows machines, as it uses the Win32 API to actually do the look-up (hence my caveat at the start of the answer). If you can be a little clearer about your requirements, I'm happy to help. – ig0774 Jun 13 '12 at 23:08
  • If you need something that will work on a non-Windows environment, you can try [the code in this blog post](http://blogs.msdn.com/b/alextch/archive/2007/06/18/sample-java-application-that-retrieves-group-membership-of-an-active-directory-user-account.aspx) (found through the comment on [this answer](http://stackoverflow.com/a/1561623/274466)) – ig0774 Jun 13 '12 at 23:10
  • Ok, our application allows different kinds of authentication: username/password, OpenAuth and Active Directory. So if in config file app is configured to have AD authentication and security group is specified, then I want to be able to automatically check logged in user (without asking for password) and check if he belongs to the specified group. I am using Apache Directory Studio to build me AD for testing. I know I should be able to use Spring LDAP, but all samples on the net show authentication where user has to provide password, I dont want that. Please help – fenix2222 Jun 14 '12 at 00:11
  • I dont want to ask for password because user is already logged in to PC. – fenix2222 Jun 14 '12 at 00:13
  • So this is a web-app, correct? And the server is not running on Windows? – ig0774 Jun 14 '12 at 02:03
  • It is a web app and server is not likely to run on windows – fenix2222 Jun 14 '12 at 02:12
  • @fenix2222: What you appear to be asking is not easy to answer. Java is not as straight-forwardly integrated into the Active Directory stack as C# for obvious reasons. See my longish edit above for some pointers on where to start. – ig0774 Jun 15 '12 at 14:34
  • Use of com.sun. packages are widely discouraged - it shouldn't be used for production critical applications as they might be deprecated/changed/takeout without notice. – avijendr Mar 01 '20 at 18:28
  • `com.sun` is discouraged when the classes in question refer to classes in the standard Java runtime because, as you say, they are generally not part of the public API. `com.sun.jna`, however, refers to classes that are part of the third-party JNA library. These classes form a documented public API (which requires the addition of a new jar) and hence don’t fall under the same rule. – ig0774 Mar 01 '20 at 18:32
  • Admittedly it is weird that a third-party package uses the `com.sun` package, but there we are. – ig0774 Mar 01 '20 at 18:38
2

You can get all the groups without JNA like this:

String groups[] = (new com.sun.security.auth.module.NTSystem()).getGroupIDs();

Obviously this will work only on Windows, and even on Windows is the use of com.sun.* packages discouraged. See this for the explanation of the result.

lbalazscs
  • 17,474
  • 7
  • 42
  • 50
0

This can be done through the Java SE APIs without using the com.sun.* packages directly. Use Java Authentication and Authorization Service (JAAS) (javax.security.auth.* and javax.security.auth.login.*) to access this information. Create a JAAS config file with the following entry:

sampleApp {
    com.sun.security.auth.module.NTLoginModule required debug=false;
};

Save that entry as sampleapp_jaas.config. Next set the system property so Java will look for the config file.

-Djava.security.auth.login.config==sampleapp_jaas.config

Note that the double equals has special meaning. See the com.sun.security.auth.login.ConfigFile for details on the load order.

Then create LoginContext that will look for the entry in the JAAS config. Call login to populate the subject then access principals which represent the user groups.

LoginContext l = new LoginContext("sampleApp");
l.login();
try {
    Subject s = l.getSubject();
    for (Principal p : s.getPrincipals()) {
        System.out.println(p);
    }
} finally {
    l.logout();
}

Using this setup, Java will use the com.sun.security.auth.module.NTSystem class to get the information but none of your code will be hardwired to the non-standard APIs.

jmehrens
  • 10,580
  • 1
  • 38
  • 47