adjust to use password-service
[aaa.git] / aaa-password-service / impl / src / main / java / org / opendaylight / aaa / impl / password / service / DefaultPasswordHashService.java
1 /*
2  * Copyright © 2018 Inocybe Technologies and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.aaa.impl.password.service;
9
10 import java.util.Optional;
11 import org.apache.shiro.codec.Base64;
12 import org.apache.shiro.crypto.SecureRandomNumberGenerator;
13 import org.apache.shiro.crypto.hash.DefaultHashService;
14 import org.apache.shiro.crypto.hash.Hash;
15 import org.apache.shiro.crypto.hash.HashRequest;
16 import org.apache.shiro.crypto.hash.SimpleHashRequest;
17 import org.apache.shiro.util.ByteSource;
18 import org.opendaylight.aaa.api.password.service.PasswordHash;
19 import org.opendaylight.aaa.api.password.service.PasswordHashService;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 public class DefaultPasswordHashService implements PasswordHashService {
25
26     private static final Logger LOG = LoggerFactory.getLogger(DefaultPasswordHashService.class);
27
28     public static final String DEFAULT_HASH_ALGORITHM = "SHA-512";
29     public static final int DEFAULT_NUM_ITERATIONS = 20000;
30
31     private final DefaultHashService hashService = new DefaultHashService();
32
33     public DefaultPasswordHashService() {
34         hashService.setRandomNumberGenerator(new SecureRandomNumberGenerator());
35         hashService.setGeneratePublicSalt(true);
36         setNumIterations(Optional.of(DEFAULT_NUM_ITERATIONS));
37         setHashAlgorithm(Optional.of(DEFAULT_HASH_ALGORITHM));
38     }
39
40     public DefaultPasswordHashService(final PasswordServiceConfig passwordServiceConfig) {
41         this();
42         final Optional<Integer> numIterationsOptional = Optional.ofNullable(passwordServiceConfig.getIterations());
43         setNumIterations(numIterationsOptional);
44
45         final Optional<String> hashAlgorithmOptional = Optional.ofNullable(passwordServiceConfig.getAlgorithm());
46         setHashAlgorithm(hashAlgorithmOptional);
47
48         final Optional<String> privateSaltOptional = Optional.ofNullable(passwordServiceConfig.getPrivateSalt());
49         setPrivateSalt(privateSaltOptional);
50     }
51
52     private void setNumIterations(final Optional<Integer> numIterationsOptional) {
53         if (numIterationsOptional.isPresent()) {
54             final Integer numIterations = numIterationsOptional.get();
55             hashService.setHashIterations(numIterations);
56             LOG.info("DefaultPasswordHashService will utilize configured iteration count={}", numIterations);
57         } else {
58             hashService.setHashIterations(DEFAULT_NUM_ITERATIONS);
59             LOG.info("DefaultPasswordHashService will utilize default iteration count={}", DEFAULT_NUM_ITERATIONS);
60         }
61     }
62
63     private void setHashAlgorithm(final Optional<String> hashAlgorithmOptional) {
64         if (hashAlgorithmOptional.isPresent()) {
65             final String hashAlgorithm = hashAlgorithmOptional.get();
66             hashService.setHashAlgorithmName(hashAlgorithm);
67             LOG.info("DefaultPasswordHashService will utilize configured algorithm={}", hashAlgorithm);
68         } else {
69             hashService.setHashAlgorithmName(DEFAULT_HASH_ALGORITHM);
70             LOG.info("DefaultPasswordHashService will utilize default algorithm={}", DEFAULT_HASH_ALGORITHM);
71         }
72     }
73
74     private void setPrivateSalt(final Optional<String> privateSaltOptional) {
75         if (privateSaltOptional.isPresent()) {
76             hashService.setPrivateSalt(ByteSource.Util.bytes(privateSaltOptional.get()));
77             LOG.info("DefaultPasswordHashService will utilize a configured private salt");
78         } else {
79             LOG.info("DefaultPasswordHashService will not utilize a private salt, since none was configured");
80         }
81     }
82
83     @Override
84     public PasswordHash getPasswordHash(final String password) {
85         final HashRequest hashRequest = new HashRequest.Builder()
86                 .setAlgorithmName(hashService.getHashAlgorithmName())
87                 .setIterations(hashService.getHashIterations())
88                 .setSource(ByteSource.Util.bytes(password)).build();
89
90         final Hash hash =  hashService.computeHash(hashRequest);
91         return PasswordHashImpl.create(
92                 hash.getAlgorithmName(),
93                 hash.getSalt().toBase64(),
94                 hash.getIterations(),
95                 hash.toBase64());
96     }
97
98     @Override
99     public PasswordHash getPasswordHash(final String password, final String salt) {
100         final HashRequest hashRequest = new SimpleHashRequest(
101                 hashService.getHashAlgorithmName(),
102                 ByteSource.Util.bytes(password),
103                 ByteSource.Util.bytes(Base64.decode(salt)),
104                 hashService.getHashIterations());
105
106         final Hash hash =  hashService.computeHash(hashRequest);
107         return PasswordHashImpl.create(
108                 hash.getAlgorithmName(),
109                 hash.getSalt().toBase64(),
110                 hash.getIterations(),
111                 hash.toBase64());
112     }
113
114     @Override
115     public boolean passwordsMatch(final String plaintext, final String stored, final String salt) {
116         final String hash = getPasswordHash(plaintext, salt).getHashedPassword();
117         return hash.equals(stored);
118     }
119 }