Move sal-netconf-connector to plugins/
[netconf.git] / plugins / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / auth / DatastoreBackedPublicKeyAuth.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. 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.netconf.sal.connect.netconf.auth;
9
10 import com.google.common.base.Strings;
11 import java.io.IOException;
12 import java.io.StringReader;
13 import java.security.KeyPair;
14 import java.util.Optional;
15 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
16 import org.opendaylight.aaa.encrypt.PKIUtil;
17 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
18 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
19 import org.opendaylight.netconf.shaded.sshd.client.future.AuthFuture;
20 import org.opendaylight.netconf.shaded.sshd.client.session.ClientSession;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.keystore.rev171017.keystore.entry.KeyCredential;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 public class DatastoreBackedPublicKeyAuth extends AuthenticationHandler {
26
27     private static final Logger LOG = LoggerFactory.getLogger(DatastoreBackedPublicKeyAuth.class);
28
29     private final String username;
30     private final String pairId;
31     private final NetconfKeystoreAdapter keystoreAdapter;
32     private final AAAEncryptionService encryptionService;
33
34     private Optional<KeyPair> keyPair = Optional.empty();
35
36     public DatastoreBackedPublicKeyAuth(final String username, final String pairId,
37                                         final NetconfKeystoreAdapter keystoreAdapter,
38                                         final AAAEncryptionService encryptionService) {
39         this.username = username;
40         this.pairId = pairId;
41         this.keystoreAdapter = keystoreAdapter;
42         this.encryptionService = encryptionService;
43
44         // try to immediately retrieve the pair from the adapter
45         tryToSetKeyPair();
46     }
47
48     @Override
49     public String getUsername() {
50         return username;
51     }
52
53     @Override
54     public AuthFuture authenticate(final ClientSession session) throws IOException {
55         // if we have keypair set the identity, otherwise retry the retrieval from the adapter
56         // if successful set the identity.
57         if (keyPair.isPresent() || tryToSetKeyPair()) {
58             session.addPublicKeyIdentity(keyPair.get());
59         }
60         return session.auth();
61     }
62
63     private boolean tryToSetKeyPair() {
64         LOG.debug("Trying to retrieve keypair for: {}", pairId);
65         final Optional<KeyCredential> keypairOptional = keystoreAdapter.getKeypairFromId(pairId);
66
67         if (keypairOptional.isPresent()) {
68             final KeyCredential dsKeypair = keypairOptional.get();
69             final String passPhrase = Strings.isNullOrEmpty(dsKeypair.getPassphrase()) ? "" : dsKeypair.getPassphrase();
70
71             try {
72                 this.keyPair = Optional.of(
73                         new PKIUtil().decodePrivateKey(
74                                 new StringReader(encryptionService.decrypt(
75                                         dsKeypair.getPrivateKey()).replaceAll("\\\\n", "\n")),
76                                 encryptionService.decrypt(passPhrase)));
77             } catch (IOException exception) {
78                 LOG.warn("Unable to decode private key, id={}", pairId, exception);
79                 return false;
80             }
81             return true;
82         }
83         LOG.debug("Unable to retrieve keypair for: {}", pairId);
84         return false;
85     }
86 }