I am trying to use Spring Data LDAP for users authentication using OpenLDAP server. However, search by uid and userPassword fails because the password is stored as SSHA hashed.
I wonder if really Spring Data LDAP can be used for users authentication because the tutorials usually concentrate on searching or they map password to some attribute other than userPassword.
#Entry(base = "ou=People", objectClasses = { "top", "person", "inetOrgPerson", "organizationalPerson", "simpleSecurityObject" })
public class LdapUser {
#Id Name dn;
#Attribute(name = "userPassword")
private String password;
/** The user id. */
#Attribute(name = "uid")
private String userName;
}
public interface ILdapUserRepo extends LdapRepository<LdapUser>{
public LdapUser findByUserNameAndPassword(String username, String password);
}
Your use-case isn't what Spring Data LDAP is intended for. Spring Data LDAP is intended to lookup objects from LDAP by querying these and updating LDAP entities.
Performing LDAP authentication requires authentication against LDAP directly by using the appropriate connectors.
Related
i´m trying to add some authentication and authorization functionality to my small web application. therefore i´m using apache shiro.
my plan: using an existing ldap server for user authentication and using a properties or ini file for authorization.
here´s a small example:
user x wants to use the application
he enters his username and his password
the ldap server is used for authentication --> user + pwd correct?
if authentication is verified and correct, a properties file or ini file is used to check if the user is permitted, to start some functions inside the application.
i hope you know what i´m trying to do.
now i´m not sure how to implement this feature. is it enough to use an ini file or is it required to implement my own realm?! is there an example implementation?
i´m grateful for every information
and sorry for my bad english :/
Yes, you have to implement a realm but this is not difficult. You just have to extend JndiLdapRealm and override the queryForAuthorizationInfo method.
This method returns an AuthorizationInfo interface type. In your case the easiest is to return an instance of SimpleAuthorizationInfo which implements this interface.
You must initialize the AuthorizationInfo with the roles and/or permissions for the authenticated user. When this method is called, the user is already authenticated but not authorized.
Inside this method you can read the authorization information from any data source that you want, it can be a properties or ini file, properties associated with the user in the LDAP server, a database or anything that pleases you.
A realm implementation could be:
package example.shiro.realm.ldap;
import javax.naming.NamingException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.realm.ldap.LdapContextFactory;
import org.apache.shiro.subject.PrincipalCollection;
public class JndiLdapAuthzRealm extends JndiLdapRealm {
private List<String> getRoles(String userName) {
List<String> roles = new ArrayList<>();
// TODO: get roles from data source and fill list
roles.add("user");
roles.add("admin");
return roles;
}
private List<String> getPermissions(String userName) {
List<String> perms = new ArrayList<>();
// TODO: get permissions from data source and fill list
perms.add("myapp:run");
perms.add("myapp:file:create");
return perms;
}
#Override
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
String userName = principals.getPrimaryPrincipal().toString();
info.addRoles(getRoles(userName));
info.addStringPermissions(getPermissions(userName));
return info;
}
}
In your case, rewrite the getRoles and getPermissions to get the roles and permissions for the authenticated user from the properties or ini file.
In shiro.ini:
[main]
ldapRealm = example.shiro.realm.ldap.JndiLdapAuthzRealm
ldapRealm.userDnTemplate = uid={0},cn=users,cn=accounts,dc=example,dc=com
ldapRealm.contextFactory.url = ldap://192.168.0.10
I'm developing a simple JAX - RS server and I need to implement Authentication and Authorization. I have found in other posts that the standard way is to use the standard Java EE web servlet container security with role-mapping in conjunction with OAuth, Form-based Authentication or Basic Authentication.
My problem is my company has a custom Authentication Provider accessible by an EJB client. The Authentication provider takes username and password in input and return a UserObject with a series of rights associated with it. If the rights list contain the one associated with my REST server, then the user is also authorized to ask for resources, otherwise a CustomAuthorizationException is thrown. In fact this is a 'one-shot Authorization', so i could enforce it with additional servlet container standard authorization.
This is an example:
String username = //acquire username;
String password = // acquire password;
UserObject user = null;
try {
user = authenticationClient.login(username, password);
if(user == null){
//erro message and forward to login page
}
verifyAuthorization(user);
} catch (CustomAuthorizationException e1) {
//manage exception
} catch (CustomAuthenticationException e2) {
//manage exception
}
How can I integrate this with JAX - RS standards?
I'm using Symfony Security with a custom User Provider in my system. It provide users via a web service.
I configure the provider according to this tutorial (http://symfony.com/doc/current/cookbook/security/custom_provider.html).
Here is the function which check the user:
public function loadUserByUsername($username)
{
$userData = webServiceCheckUser($username);
// return an array whit user credentials
if ($userData) {
$password = $userData['password'];
$salt = $userData['salt'];
$roles = $userData['roles'];
$user = new WebserviceUser($username, $password, $salt, $roles);
return $user;
}
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
This works fine, the function webServiceCheckUser() call a web service with the username and then it return an array with user data. But now I need to check the user through another web service that requires the username and encrypted password of the user to authenticate him.
I have a function that encrypts the plain text password like the web service is waiting, but I can't get the password that was typed by the user in the form login within the custom user provider class. It is ok too if I could get the password already encrypted. Either one solve the problem.
There is anyway to do this?
#Pazi is correct in that building your own custom authentication provider will work. However, it's not an easy task.
An alternative approach is to override DaoAuthenticationProvider and have it pass the password to the loadUser function.
security_listeners.xml:
<parameter key="security.authentication.provider.dao.class">
Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider
</parameter>
Bit of a hack perhaps but it saves a good deal of work.
I am new to LDAP authentication. I want to authenticate the users with their LDAP credentials.
For that I got the application credential from server so that I can authenticate other users.
My credential as application user are as:
Test LDAP Server IP: xx.xx.xx.xx
Port: 389
Bind DN:uid=uidxx,ou=applications,dc=dcxx
password: passxx
For authenticating the this user, I have written the code as
public String ldap()
{
String value=null;
SearchControls constraints= new SearchControls();
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://xx.xx.xx.xx:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"uid=uidxx, ou=applications, dc=dcxx");
env.put(Context.SECURITY_CREDENTIALS,"passxx");
try {
DirContext ctx = new InitialDirContext(env);
value = "Done with it";
}
catch(AuthenticationException e)
{
value = "Invalid User name or password";
}
catch (NamingException e) {
e.printStackTrace();
value = "Exception occurred";
}
return value;
}
I got return value as "Done with it"
Now i want to authenticate other user whose mail id and password is known to me.
Its like i want authenticate other users using their mailid, password, and for that i got uidxx and passxx to authenticate them.
How should i do that?
Not getting much help from the other sources.
Thank you
When authenticating against LDAP common work flow is
Bind to LDAP using credentials you have. This user have to have at least read-only access to subtree with users. Often it is ou=People, ou=Domain, dc=com or similar.
Query LDAP server for user's DN (here is where ANR might be useful)
Try to bind to LDAP using user's DN and password supplied to your application
This works because it is very common to give every user RW rights to his object in database. Very useful if you want user to be able to change their own password.
I have a WCF service with security mode set to message. I use Username for client credentials type with a custom UserNamePasswordValidator.
NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message, false);
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
Can I retrieve the password on server side, after the user is authenticated?
Is the password saved in MessageHeader of the request? Can I get it from MessageHeader (after user is authenticated)?
Angela
As far as I understand your question you have a WCF service which requires a user name and password for authentication. You have configured a custom UserNamePasswordValidator for this purpose instead of relying on the default mechanism employed by WCF (= Windows).
Take a look here for more information on how to setup a custom username and pasword validator in WCF:
http://msdn.microsoft.com/en-us/library/aa702565.aspx
I assume you have created a class that dervies from the UserNamePasswordValidator type. Your custom type is responsible for checking the username and password against a store (database, xml file...etc.) which contains a list of your users. The validator must determine if it is dealing with a valid user. If so, it can authenticate the user.
For example:
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
// Validator username and password here
// bool isValid = ...;
if (!isValid)
{
throw new SecurityTokenException("Access denied.");
}
}
}
As you can see if you correctly implemented the custom UserNamePasswordValidator you already have a place where you can access the username and password which the client submitted.
If you want to access the username after the user has been authenticated, for instance in the body of one of service's methods you can use the following:
var userName =
OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
Take a look at the ServiceSecurityContext type for more information.
If you also want to make the password available, then I suggest you take a look at the following article:
http://www.neovolve.com/post/2008/04/07/wcf-security-getting-the-password-of-the-user.aspx
I guess you could also extract the username and password from the current OperationContext as one of the comments of the previously mentioned article suggests.
public void MyServiceMethod()
{
var context = OperationContext.Current;
var token = context.IncomingMessageProperties.Security
.IncomingSupportingTokens[0].SecurityToken as
System.IdentityModel.Tokens.UserNameSecurityToken;
//...
}