Reputation: 309
We need to authenticate through Active Directory. We would like if our Windows users inside the domain could authenticate without putting in username and password (Single Sign On), but also external users (or users not using Internet Explorer) being able to insert their username and password and login.
We also need to put out hands in the groups that the user is member, because this will change what this user will be able to see in our website.
We are using Java with Jetty as our application server, and developing in Windows but our server will be Linux.
Thank you!
Upvotes: 2
Views: 2178
Reputation: 14156
As suggested by @Akber you can use the IP range. You need a public endpoint that will use the remote address or the X-Forwarded-For header, with the IP you can test if it is inside the intranet range, this is 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/12
.
If the IP is in the intranet range you can redirect to an Apache Proxy (more on this later). If the IP is out of the range you redirect to an endpoint with a nice looking form.
Apache with mod_auth_kerb is one of the only ways that have worked for us in Linux for this scenario. You can configure apache as a kerberos proxy, it will negotiate kerberos and then call your backend with a header. This is an example piece of configuration:
ProxyPass / http://localhost:9005/ #your backend
ProxyPassReverse / http://localhost:9005/ #your backend
ProxyPreserveHost On
## Rewrite rules
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
## Request header rules
## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#requestheader
RequestHeader set X-Forwarded-User %{RU}e
<Location />
AuthName "Kerberos Login"
AuthType Kerberos
Krb5Keytab /path/to your keytab/HTTP.keytab
KrbAuthRealm DOMAIN.LOC
KrbMethodNegotiate on
KrbSaveCredentials off
KrbVerifyKDC off
KrbServiceName HTTP/YOURAPP.AD2008R2.LOC
Require valid-user
</Location>
Then you backend will receive the X-Forwarded-User
and you can use LDAP to fetch the full profile and the groups recursively.
Notice there is a /path/to your keytab/HTTP.keytab
, this file should be generated from a Windows machine bound to the domain.
This is handled directly by your application, once you receive and username and password you will have to try to "bind" to AD using the LDAP protocol, then you have to fetch the user profile and groups recursively.
It might seem simple, but it actually involves a lot of work on your side, not only code but maintenance as well. There are other two solutions that might work in your case but it requires to deploy another product;
Disclaimer: I work for Auth0.
Upvotes: 3
Reputation: 8617
If the external users can be authenticated, you might have a requirement of storing the usernames (atleast) within your application database.
You can get the user group information through AD implementation of LDAP using JNDI (which would require a few standard entries to your web.xml too).
You can use NTLM authentication through JCIFS for internal AD users on your intranet.
Based on this assumption:
Use this NTLMFilter implementation created in step 1 for single sign on for the user within the intranet using NTLM authentication through JCIFS: like this
public static Boolean authenticateUsingJCIF (String username, String password) {
UniAddress uniaddress = null;
String _methodName = "authenticateUsingJCIF";
try {
uniaddress = UniAddress.getByName(PropertyUtils
.getProperty(AUTHENTICATION_SERVER_URL));
NtlmPasswordAuthentication ntlmpasswordauthentication = new NtlmPasswordAuthentication(PropertyUtils.getProperty(AUTHENTICATION_SERVER_DOMAIN),username, password); //You can have your own method to read properties, I've just delegated to a generic utils
SmbSession.logon(uniaddress, ntlmpasswordauthentication);
logger.info("INTERNAL User authenticated successfully against AD");
} catch (UnknownHostException e) {
logger.error(e.toString(), e);
return false;
} catch (SmbException e) {
logger.error(e.toString(), e);
return false;
} catch (Exception e) {
logger.error(e.toString(), e);
return false;
}
return true;
}
For external users have a normal username/password validation: like this
private String authenticateExternalUser(String id, YourUserNamePasswordAuthenticationSource authSource) { String statusMessage = null;
logger
.info("Performing credential verification for external user against INTERNAL DB");
//Create or utilize your own handlers to validate plain/encoded credentials against internal db
CredentialVerificationResult returnCode = _handler
.verifyInternalCredential(id, authSource.getPassword());
logger.info("Logging value of return code" + returnCode.getMessage());
if (returnCode == CredentialVerificationResult.SUCCESS) {
statusMessage = CREDENTIAL_VERIFICATION_SUCCESS;
} else if (returnCode == CredentialVerificationResult.BAD_USER_ID) {
statusMessage = BAD_USER_ID;
} else if (returnCode == CredentialVerificationResult.WAIT_TO_RETRY) {
statusMessage = WAIT_TO_RETRY;
} else if (returnCode == CredentialVerificationResult.CREDENTIAL_LOCKED) {
statusMessage = CREDENTIAL_LOCKED;
} else if (returnCode == CredentialVerificationResult.PASSWORD_MISMATCH) {
statusMessage = PASSWORD_MISMATCH;
}
return statusMessage;
}
You might want to have a common method to validate internal/external users (to invoke the above 2 methods) and return your results accordingly.
Hope it helps, and good luck!
Upvotes: 0
Reputation: 1785
For group personalisation, the web app would need to know where a user came from (Intranet or Internet) and that can be done through headers, IP range configuration in Apache etc. -- it depends on your detailed configuration and code.
For Intranet SSO, it appears that you need SPNEGO, link below. For Intranet SSO, your company's administration policies and Internet Explorer settings will play a big role, so I am copying the checklist from the page:
http://wiki.eclipse.org/Jetty/Howto/Spnego
Upvotes: 0