Add NetconfMessage.of(Document) method
[netconf.git] / plugins / netconf-client-mdsal / src / main / java / org / opendaylight / netconf / client / mdsal / 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.client.mdsal;
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.client.mdsal.api.CredentialProvider;
18 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
19 import org.opendaylight.netconf.shaded.sshd.client.future.AuthFuture;
20 import org.opendaylight.netconf.shaded.sshd.client.session.ClientSession;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 public final class DatastoreBackedPublicKeyAuth extends AuthenticationHandler {
25     private static final Logger LOG = LoggerFactory.getLogger(DatastoreBackedPublicKeyAuth.class);
26
27     private final String username;
28     private final String pairId;
29     private final CredentialProvider credentialProvider;
30     private final AAAEncryptionService encryptionService;
31
32     // FIXME: do not use Optional here and deal with atomic set
33     private Optional<KeyPair> keyPair = Optional.empty();
34
35     public DatastoreBackedPublicKeyAuth(final String username, final String pairId,
36                                         final CredentialProvider credentialProvider,
37                                         final AAAEncryptionService encryptionService) {
38         this.username = username;
39         this.pairId = pairId;
40         this.credentialProvider = credentialProvider;
41         this.encryptionService = encryptionService;
42
43         // try to immediately retrieve the pair from the adapter
44         tryToSetKeyPair();
45     }
46
47     @Override
48     public String getUsername() {
49         return username;
50     }
51
52     @Override
53     public AuthFuture authenticate(final ClientSession session) throws IOException {
54         // if we have keypair set the identity, otherwise retry the retrieval from the adapter
55         // if successful set the identity.
56         if (keyPair.isPresent() || tryToSetKeyPair()) {
57             session.addPublicKeyIdentity(keyPair.orElseThrow());
58         }
59         return session.auth();
60     }
61
62     private boolean tryToSetKeyPair() {
63         LOG.debug("Trying to retrieve keypair for: {}", pairId);
64         final var dsKeypair = credentialProvider.credentialForId(pairId);
65         if (dsKeypair == null) {
66             LOG.debug("Unable to retrieve keypair for: {}", pairId);
67             return false;
68         }
69
70         final String passPhrase = Strings.isNullOrEmpty(dsKeypair.getPassphrase()) ? "" : dsKeypair.getPassphrase();
71         try {
72             keyPair = Optional.of(new PKIUtil().decodePrivateKey(
73                 new StringReader(encryptionService.decrypt(dsKeypair.getPrivateKey()).replace("\\n", "\n")),
74                 encryptionService.decrypt(passPhrase)));
75         } catch (IOException exception) {
76             LOG.warn("Unable to decode private key, id={}", pairId, exception);
77             return false;
78         }
79         return true;
80     }
81 }