Troncador
Troncador

Reputation: 3536

failed in the authentication using Shiro

I have to create a custom realm in Shiro and I have to use a password with "salt"

The code I use is something like:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken  authenticationToken) 
        throws AuthenticationException {
    ...
    Admin admin = query.getByUsername(username);    
    String passwordSalted = admin.getPassword();

    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, passwordSalted, new SimpleByteSource(MY_PRIVATE_SALT), getName());
    return info;
}

public Admin createAdmin(AuthenticationToken authenticationToken){
    DefaultHashService hashService = new DefaultHashService();
    hashService.setHashIterations(500000);
    hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
    hashService.setPrivateSalt(new SimpleByteSource(MY_PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded.
    hashService.setGeneratePublicSalt(true);

    DefaultPasswordService passwordService = new DefaultPasswordService();
    passwordService.setHashService(hashService);
    String encryptedPassword = passwordService.encryptPassword(authenticationToken.getCredentials());

    Admin admin = new Admin();
    String principal = authenticationToken.getPrincipal().toString();
    admin.setUsername(principal);
    admin.setPassword(encryptedPassword);
    return admin;
}

I use the function "createAdmin" to create a Admin, then I store it in the database, like this:

UsernamePasswordToken u = new UsernamePasswordToken("foo","qwerty") ;
Admin admin = createAdmin(u);
query.save(admin);

The password saved is something like:

$shiro1$SHA-256$50000$M7T93MZ65TCxXBsD7JFa9A==$gJcEf2oSKE/RKXifwYiJCaHU7X10ng1PxqL3AEMvmjE=

I don't know why it failed to authenticated:

 Factory<SecurityManager> factory = 
            new IniSecurityManagerFactory("classpath:shiro.ini");
 SecurityManager securityManager = factory.getInstance();
 SecurityUtils.setSecurityManager(securityManager);
 AuthenticationToken authenticationToken = new UsernamePasswordToken("foo", "qwerty");

 Subject usr = SecurityUtils.getSubject();
 try {
    securityManager.login(usr, authenticationToken);
 } catch (Exception e) {
        log.error("error");
 }

And my shiro.ini:

 [main]
 customSecurityRealm=cl.fooproyect.CustomRealm

Solved:

To solve the problem I have to change shiro.ini and the createAdmin. I let to the responsability to shiro to create the salt. This solution work for me.

Changes in shiro.ini

 [main]

 passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
 passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
 passwordMatcher.passwordService = $passwordService

 customSecurityRealm=cl.doman.punto.vaadin.shiro.CustomRealm
 customSecurityRealm.credentialsMatcher = $passwordMatcher

 securityManager.realms = $customSecurityRealm

Changes in createAdmin:

 public Admin createAdmin(AuthenticationToken authenticationToken){
    DefaultHashService hashService = new DefaultHashService();

    DefaultPasswordService passwordService = new DefaultPasswordService();
    String encryptedPassword =      passwordService.encryptPassword(authenticationToken.getCredentials());

    Admin admin = new Admin();
    String principal = authenticationToken.getPrincipal().toString();
    admin.setUsername(principal);
    admin.setPassword(encryptedPassword);
    return admin;
}

Upvotes: 1

Views: 2855

Answers (1)

Wouter
Wouter

Reputation: 4016

You need to make sure your realm uses the same passwordhashing settings as when creating the users.

If you use spring, you can make beans of them, but if you're not using anything like that, you can use the idea below to create some kind of factory to create one object of each of the services needed.

Anyway, here is how we configured our password/hashing/custom realm.

First create the password service:

@Configuration
public class SecurityConfiguration {

    private static final String PRIVATE_SALT = "ourprivatesalt";

    private PasswordService passwordService;

    private PasswordMatcher credentialsMatcher = new PasswordAndSystemCredentialsMatcher();


    private AuthenticatingSecurityManager securityManager;

    @Bean
    public PasswordService passwordService() {
        if (passwordService == null) {
           DefaultPasswordService defaultPasswordService = new DefaultPasswordService();
           passwordService = defaultPasswordService;
           DefaultHashService defaultHashService = (DefaultHashService) defaultPasswordService.getHashService();
           defaultHashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT));
        }
        return passwordService;
    }

    @Bean
    public CredentialsMatcher credentialsMatcher() {
        credentialsMatcher.setPasswordService(passwordService());
        return credentialsMatcher;
    }

And then our custom realm:

@Service
public class OurRealmImpl extends AuthorizingRealm {

    @Autowired
    private CredentialsMatcher credentialsMatcher;

    @PostConstruct
    private void configure() {
        setCredentialsMatcher(credentialsMatcher);
    }

Looking at your code, I think the missing thing is that you did not change the credentials matcher in your custom realm.

Upvotes: 1

Related Questions