001/*
002 * Copyright 2012 Atteo.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.atteo.moonshine.shiro.database;
017
018import org.apache.shiro.authc.AuthenticationException;
019import org.apache.shiro.authc.AuthenticationInfo;
020import org.apache.shiro.authc.AuthenticationToken;
021import org.apache.shiro.authc.SimpleAuthenticationInfo;
022import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
023import org.apache.shiro.codec.Hex;
024import org.apache.shiro.crypto.RandomNumberGenerator;
025import org.apache.shiro.crypto.SecureRandomNumberGenerator;
026import org.apache.shiro.crypto.hash.SimpleHash;
027import org.apache.shiro.realm.AuthenticatingRealm;
028import org.apache.shiro.subject.SimplePrincipalCollection;
029import org.apache.shiro.util.ByteSource;
030import org.apache.shiro.util.SimpleByteSource;
031
032import com.google.inject.Inject;
033
034public class DatabaseRealm extends AuthenticatingRealm {
035    private final int hashIterations = 1536;
036    private final String hashAlgorithm = "SHA-256";
037    private final RandomNumberGenerator randomNumberGenerator;
038
039    @Inject
040    private AccountRepository accountRepository;
041
042    public DatabaseRealm() {
043        this.randomNumberGenerator = new SecureRandomNumberGenerator();
044
045        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(hashAlgorithm);
046        credentialsMatcher.setHashIterations(hashIterations);
047        setCredentialsMatcher(credentialsMatcher);
048
049        setName("LoginRealm");
050    }
051
052    public int getHashIterations() {
053        return hashIterations;
054    }
055
056    public String getHashAlgorithm() {
057        return hashAlgorithm;
058    }
059
060    public ByteSource generateSalt() {
061        return randomNumberGenerator.nextBytes();
062    }
063
064    public String hashPassword(String password, ByteSource salt) {
065        return new SimpleHash(hashAlgorithm, password, salt, hashIterations).toHex();
066    }
067
068    @Override
069    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
070            throws AuthenticationException {
071        String principal = (String) token.getPrincipal();
072        Account loginAccount = accountRepository.findOne(principal);
073
074        SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(
075                loginAccount.getLogin(), getName());
076
077        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principalCollection,
078                loginAccount.getHashedPassword(), new SimpleByteSource(Hex.decode(loginAccount
079                .getSalt())));
080
081        return info;
082    }
083}