Bug 8095: Add operational devices to call home collection.
[netconf.git] / netconf / callhome-protocol / src / main / java / org / opendaylight / netconf / callhome / protocol / CallHomeAuthorization.java
1 /*
2  * Copyright (c) 2016 Brocade Communication Systems 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.callhome.protocol;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableSet;
12 import java.security.KeyPair;
13 import java.util.Collection;
14 import java.util.HashSet;
15 import java.util.Set;
16 import org.apache.sshd.ClientSession;
17 import org.apache.sshd.client.session.ClientSessionImpl;
18
19 /**
20  * Authorization context for incoming call home sessions.
21  *
22  * @see CallHomeAuthorizationProvider
23  */
24 public abstract class CallHomeAuthorization {
25     private static final CallHomeAuthorization REJECTED = new CallHomeAuthorization() {
26
27         @Override
28         public boolean isServerAllowed() {
29             return false;
30         }
31
32         @Override
33         protected String getSessionName() {
34             return "";
35         }
36
37         @Override
38         protected void applyTo(ClientSession session) {
39             throw new IllegalStateException("Server is not allowed.");
40         }
41     };
42
43     /**
44      * Returns CallHomeAuthorization object with intent to
45      * reject incoming connection.
46      * <p>
47      * {@link CallHomeAuthorizationProvider} may use returned object
48      * as return value for {@link CallHomeAuthorizationProvider#provideAuth(java.net.SocketAddress, java.security.PublicKey)}
49      * if the incoming session should be rejected due to policy implemented
50      * by provider.
51      *
52      * @return CallHomeAuthorization with {@code isServerAllowed() == false}
53      */
54     public static final CallHomeAuthorization rejected() {
55         return REJECTED;
56     }
57
58     /**
59      * Creates a builder for CallHomeAuthorization with intent
60      * to accept incoming connection and to provide credentials.
61      * <p>
62      * Note: If session with same sessionName is already opened and
63      * active, incoming session will be rejected.
64      *
65      * @param sessionName Application specific unique identifier for incoming session
66      * @param username    Username to be used for authorization
67      * @return Builder which allows to specify credentials.
68      */
69     public static final Builder serverAccepted(String sessionName, String username) {
70         return new Builder(sessionName, username);
71     }
72
73     /**
74      * Returns true if incomming connection is allowed.
75      *
76      * @return true if incoming connection from SSH Server is allowed.
77      */
78     public abstract boolean isServerAllowed();
79
80     /**
81      * Applies provided authentification to Mina SSH Client Session
82      *
83      * @param session Client Session to which authorization parameters will by applied
84      */
85     protected abstract void applyTo(ClientSession session);
86
87     protected abstract String getSessionName();
88
89     /**
90      * Builder for CallHomeAuthorization which accepts incoming connection.
91      * <p>
92      * Use {@link CallHomeAuthorization#serverAccepted(String, String)} to instantiate
93      * builder.
94      */
95     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CallHomeAuthorization> {
96
97         private final String nodeId;
98         private final String username;
99         private Set<String> passwords = new HashSet<>();
100         private Set<KeyPair> clientKeys = new HashSet<>();
101
102         private Builder(String nodeId, String username) {
103             this.nodeId = Preconditions.checkNotNull(nodeId);
104             this.username = Preconditions.checkNotNull(username);
105         }
106
107         /**
108          * Adds password, which will be used for password-based authorization.
109          *
110          * @param password Password to be used for password-based authorization.
111          * @return this builder.
112          */
113         public Builder addPassword(String password) {
114             this.passwords.add(password);
115             return this;
116         }
117
118         /**
119          * Adds public / private key pair to be used for public-key based authorization.
120          *
121          * @param clientKey Keys to be used for authorization.
122          * @return this builder.
123          */
124         public Builder addClientKeys(KeyPair clientKey) {
125             this.clientKeys.add(clientKey);
126             return this;
127         }
128
129         @Override
130         public CallHomeAuthorization build() {
131             return new ServerAllowed(nodeId, username, passwords, clientKeys);
132         }
133
134     }
135
136     private static class ServerAllowed extends CallHomeAuthorization {
137
138         private final String nodeId;
139         private final String username;
140         private final Set<String> passwords;
141         private final Set<KeyPair> clientKeyPair;
142
143         ServerAllowed(String nodeId, String username, Collection<String> passwords, Collection<KeyPair> clientKeyPairs) {
144             this.username = Preconditions.checkNotNull(username);
145             this.passwords = ImmutableSet.copyOf(passwords);
146             this.clientKeyPair = ImmutableSet.copyOf(clientKeyPairs);
147             this.nodeId = Preconditions.checkNotNull(nodeId);
148         }
149
150         @Override
151         protected String getSessionName() {
152             return nodeId;
153         }
154
155         @Override
156         public boolean isServerAllowed() {
157             return true;
158         }
159
160         @Override
161         protected void applyTo(ClientSession session) {
162             Preconditions.checkArgument(session instanceof ClientSessionImpl);
163             ((ClientSessionImpl) session).setUsername(username);
164
165             // First try authentication using server host keys, else try password.
166             for (KeyPair keyPair : clientKeyPair) {
167                 session.addPublicKeyIdentity(keyPair);
168             }
169             for (String password : passwords) {
170                 session.addPasswordIdentity(password);
171             }
172         }
173     }
174 }