f4d1c00ee257f5b44bfa691e1879db510900773d
[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 org.apache.shiro.codec.Base64;
11 import org.apache.shiro.crypto.hash.DefaultHashService;
12 import org.apache.shiro.crypto.hash.Hash;
13 import org.apache.shiro.crypto.hash.HashRequest;
14 import org.apache.shiro.crypto.hash.SimpleHashRequest;
15 import org.apache.shiro.util.ByteSource;
16 import org.opendaylight.aaa.api.password.service.PasswordHash;
17 import org.opendaylight.aaa.api.password.service.PasswordHashService;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfigBuilder;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 public class DefaultPasswordHashService implements PasswordHashService {
24     private static final Logger LOG = LoggerFactory.getLogger(DefaultPasswordHashService.class);
25
26     public static final String DEFAULT_HASH_ALGORITHM = "SHA-512";
27     public static final int DEFAULT_NUM_ITERATIONS = 20000;
28
29     private final DefaultHashService hashService;
30
31     public DefaultPasswordHashService() {
32         this(new PasswordServiceConfigBuilder().build());
33     }
34
35     public DefaultPasswordHashService(final PasswordServiceConfig passwordServiceConfig) {
36         hashService = createHashService(passwordServiceConfig.getIterations(), passwordServiceConfig.getAlgorithm(),
37             passwordServiceConfig.getPrivateSalt());
38     }
39
40     @Override
41     public PasswordHash getPasswordHash(final String password) {
42         final HashRequest hashRequest = new HashRequest.Builder()
43                 .setAlgorithmName(hashService.getHashAlgorithmName())
44                 .setIterations(hashService.getHashIterations())
45                 .setSource(ByteSource.Util.bytes(password)).build();
46
47         final Hash hash =  hashService.computeHash(hashRequest);
48         return PasswordHashImpl.create(
49                 hash.getAlgorithmName(),
50                 hash.getSalt().toBase64(),
51                 hash.getIterations(),
52                 hash.toBase64());
53     }
54
55     @Override
56     public PasswordHash getPasswordHash(final String password, final String salt) {
57         final HashRequest hashRequest = new SimpleHashRequest(
58                 hashService.getHashAlgorithmName(),
59                 ByteSource.Util.bytes(password),
60                 ByteSource.Util.bytes(Base64.decode(salt)),
61                 hashService.getHashIterations());
62
63         final Hash hash =  hashService.computeHash(hashRequest);
64         return PasswordHashImpl.create(
65                 hash.getAlgorithmName(),
66                 hash.getSalt().toBase64(),
67                 hash.getIterations(),
68                 hash.toBase64());
69     }
70
71     @Override
72     public boolean passwordsMatch(final String plaintext, final String stored, final String salt) {
73         return getPasswordHash(plaintext, salt).getHashedPassword().equals(stored);
74     }
75
76     private static DefaultHashService createHashService(final Integer numIterations, final String hashAlgorithm,
77             final String privateSalt) {
78         final DefaultHashService hashService = new DefaultHashService();
79
80         if (numIterations != null) {
81             hashService.setHashIterations(numIterations);
82             LOG.info("DefaultPasswordHashService will utilize configured iteration count={}", numIterations);
83         } else {
84             hashService.setHashIterations(DEFAULT_NUM_ITERATIONS);
85             LOG.info("DefaultPasswordHashService will utilize default iteration count={}", DEFAULT_NUM_ITERATIONS);
86         }
87
88         if (hashAlgorithm != null) {
89             hashService.setHashAlgorithmName(hashAlgorithm);
90             LOG.info("DefaultPasswordHashService will utilize configured algorithm={}", hashAlgorithm);
91         } else {
92             hashService.setHashAlgorithmName(DEFAULT_HASH_ALGORITHM);
93             LOG.info("DefaultPasswordHashService will utilize default algorithm={}", DEFAULT_HASH_ALGORITHM);
94         }
95
96         if (privateSalt != null) {
97             hashService.setPrivateSalt(ByteSource.Util.bytes(privateSalt));
98             LOG.info("DefaultPasswordHashService will utilize a configured private salt");
99         } else {
100             hashService.setGeneratePublicSalt(true);
101             LOG.info("DefaultPasswordHashService will not utilize a private salt, since none was configured");
102         }
103
104         return hashService;
105     }
106 }