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