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