fecf2f03da9a1a5aa2e1cba502610e6d03eb1ec2
[aaa.git] / aaa-shiro / impl / src / test / java / org / opendaylight / aaa / impl / shiro / realm / KeystoneAuthRealmTest.java
1 /*
2  * Copyright (c) 2017 Ericsson 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
9 package org.opendaylight.aaa.shiro.realm;
10
11
12 import static org.hamcrest.Matchers.arrayContaining;
13 import static org.hamcrest.Matchers.is;
14 import static org.hamcrest.Matchers.notNullValue;
15 import static org.junit.Assert.assertThat;
16 import static org.mockito.Matchers.any;
17 import static org.mockito.Matchers.same;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.verify;
20 import static org.mockito.Mockito.when;
21
22 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
23 import java.net.MalformedURLException;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import java.util.List;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29 import javax.net.ssl.HttpsURLConnection;
30 import javax.net.ssl.SSLContext;
31 import javax.ws.rs.HttpMethod;
32 import javax.ws.rs.core.MediaType;
33 import org.apache.shiro.authc.AuthenticationException;
34 import org.apache.shiro.authc.AuthenticationInfo;
35 import org.apache.shiro.authc.AuthenticationToken;
36 import org.apache.shiro.authc.UsernamePasswordToken;
37 import org.junit.Assert;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.ArgumentCaptor;
42 import org.mockito.Captor;
43 import org.mockito.Mock;
44 import org.mockito.Spy;
45 import org.mockito.runners.MockitoJUnitRunner;
46 import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
47 import org.opendaylight.aaa.cert.api.ICertificateManager;
48 import org.opendaylight.aaa.impl.AAAShiroProvider;
49 import org.opendaylight.aaa.impl.shiro.keystone.domain.KeystoneAuth;
50 import org.opendaylight.aaa.impl.shiro.keystone.domain.KeystoneToken;
51 import org.opendaylight.aaa.impl.shiro.realm.util.http.SimpleHttpClient;
52 import org.opendaylight.aaa.impl.shiro.realm.util.http.SimpleHttpRequest;
53 import org.opendaylight.aaa.impl.shiro.realm.util.http.UntrustedSSL;
54 import org.osgi.service.http.HttpService;
55
56 @RunWith(MockitoJUnitRunner.class)
57 public class KeystoneAuthRealmTest {
58
59     @Mock
60     private SimpleHttpRequest.Builder<KeystoneToken> builder;
61
62     @Mock
63     private ICertificateManager certificateManager;
64
65     @Mock
66     private SSLContext sslContext;
67
68     @Mock
69     private SimpleHttpRequest.Builder<KeystoneToken> requestBuilder;
70
71     @Mock
72     private SimpleHttpRequest<KeystoneToken> httpRequest;
73
74     @Mock
75     private SimpleHttpClient.Builder clientBuilder;
76
77     @Mock
78     private SimpleHttpClient client;
79
80     @Mock
81     private KeystoneToken response;
82
83     @Captor
84     private ArgumentCaptor<KeystoneAuth> keystoneAuthArgumentCaptor;
85
86     @Spy
87     private KeystoneAuthRealm keystoneAuthRealm;
88
89     private KeystoneToken.Token ksToken;
90
91     @Before
92     public void setup() throws MalformedURLException, URISyntaxException {
93         AAAShiroProvider.newInstance(null, null, null, null, mock(HttpService.class), null, null, null, null, null);
94
95         final String testUrl = "http://example.com";
96         // a token for a user without roles
97         ksToken = new KeystoneToken.Token();
98
99         when(certificateManager.getServerContext()).thenReturn(sslContext);
100         when(client.requestBuilder(KeystoneToken.class)).thenReturn(requestBuilder);
101         when(clientBuilder.provider(JacksonJsonProvider.class)).thenReturn(clientBuilder);
102         when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
103         when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
104         when(clientBuilder.build()).thenReturn(client);
105         when(requestBuilder.uri(new URL(testUrl).toURI())).thenReturn(requestBuilder);
106         when(requestBuilder.path("v3/auth/tokens")).thenReturn(requestBuilder);
107         when(requestBuilder.method(HttpMethod.POST)).thenReturn(requestBuilder);
108         when(requestBuilder.mediaType(MediaType.APPLICATION_JSON_TYPE)).thenReturn(requestBuilder);
109         when(requestBuilder.entity(any())).thenReturn(requestBuilder);
110         when(requestBuilder.queryParam("nocatalog", "")).thenReturn(requestBuilder);
111         when(requestBuilder.build()).thenReturn(httpRequest);
112         when(builder.queryParam(any(String.class), any(String.class))).thenReturn(builder);
113         when(httpRequest.execute()).thenReturn(response);
114         when(response.getToken()).thenReturn(ksToken);
115
116         keystoneAuthRealm.setUrl(testUrl);
117     }
118
119     @Test
120     public void doGetAuthenticationInfo() throws Exception {
121         UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
122         final AuthenticationInfo info = keystoneAuthRealm.doGetAuthenticationInfo(token, client);
123         verify(requestBuilder).entity(keystoneAuthArgumentCaptor.capture());
124         KeystoneAuth keystoneAuth = keystoneAuthArgumentCaptor.getValue();
125         assertThat(keystoneAuth.getAuth().getIdentity().getMethods(), arrayContaining("password"));
126         assertThat(keystoneAuth.getAuth().getIdentity().getPassword().getUser().getName(), is("user"));
127         assertThat(keystoneAuth.getAuth().getIdentity().getPassword().getUser().getPassword(), is("password"));
128         assertThat(keystoneAuth.getAuth().getIdentity().getPassword().getUser().getDomain().getName(),
129                 is("Default"));
130         assertThat(info, notNullValue());
131         ODLPrincipal principal = (ODLPrincipal) info.getPrincipals().getPrimaryPrincipal();
132         assertThat(principal.getUsername(), is("user"));
133         assertThat(principal.getUserId(), is("user@Default"));
134         assertThat(principal.getDomain(), is("Default"));
135         char[] credentials = (char[]) info.getCredentials();
136         assertThat(new String(credentials), is("password"));
137     }
138
139     @Test
140     public void doGetAuthenticationInfoNotAuthorized() throws Exception {
141         UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
142         AuthenticationInfo info = keystoneAuthRealm.doGetAuthenticationInfo(token, client);
143         Assert.assertFalse(info.getPrincipals().isEmpty());
144         Assert.assertTrue(info.getPrincipals().asSet().size() == 1);
145         ODLPrincipal authData = (ODLPrincipal) info.getPrincipals().asList().get(0);
146         Assert.assertEquals(0, authData.getRoles().size());
147     }
148
149     @Test
150     public void doGetAuthenticationInfoAuthorized() throws Exception {
151         // update the response mock
152         List<KeystoneToken.Token.Role> theRoles = Stream.of("admin", "ninja", "death-star-commander")
153                 .map(roleName -> new KeystoneToken.Token.Role(roleName, roleName)).collect(Collectors.toList());
154         ksToken = new KeystoneToken.Token(theRoles);
155         when(response.getToken()).thenReturn(ksToken);
156
157         UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
158         AuthenticationInfo info = keystoneAuthRealm.doGetAuthenticationInfo(token, client);
159         Assert.assertFalse(info.getPrincipals().isEmpty());
160         Assert.assertTrue(info.getPrincipals().asSet().size() == 1);
161         ODLPrincipal authData = (ODLPrincipal) info.getPrincipals().asList().get(0);
162         Assert.assertEquals(3, authData.getRoles().size());
163     }
164
165     @Test
166     public void doGetAuthenticationInfoCustomDefaultDomain() throws Exception {
167         UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
168         keystoneAuthRealm.setDefaultDomain("sdn");
169         AuthenticationInfo info = keystoneAuthRealm.doGetAuthenticationInfo(token, client);
170         verify(requestBuilder).entity(keystoneAuthArgumentCaptor.capture());
171         KeystoneAuth keystoneAuth = keystoneAuthArgumentCaptor.getValue();
172         assertThat(keystoneAuth.getAuth().getIdentity().getPassword().getUser().getDomain().getName(),
173                 is("sdn"));
174         assertThat(info, notNullValue());
175         ODLPrincipal principal = (ODLPrincipal) info.getPrincipals().getPrimaryPrincipal();
176         assertThat(principal.getUserId(), is("user@sdn"));
177         assertThat(principal.getDomain(), is("sdn"));
178     }
179
180     @Test
181     public void doGetAuthenticationInfoCustomDomain() throws Exception {
182         UsernamePasswordToken token = new UsernamePasswordToken("user@sdn", "password");
183         AuthenticationInfo info = keystoneAuthRealm.doGetAuthenticationInfo(token, client);
184         verify(requestBuilder).entity(keystoneAuthArgumentCaptor.capture());
185         KeystoneAuth keystoneAuth = keystoneAuthArgumentCaptor.getValue();
186         assertThat(keystoneAuth.getAuth().getIdentity().getPassword().getUser().getDomain().getName(),
187                 is("sdn"));
188         assertThat(info, notNullValue());
189         ODLPrincipal principal = (ODLPrincipal) info.getPrincipals().getPrimaryPrincipal();
190         assertThat(principal.getUserId(), is("user@sdn"));
191         assertThat(principal.getDomain(), is("sdn"));
192     }
193
194     @Test(expected = AuthenticationException.class)
195     public void doGetAuthenticationInfoNullSslContext() throws Exception {
196         final UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
197         when(certificateManager.getServerContext()).thenReturn(null);
198         keystoneAuthRealm.doGetAuthenticationInfo(token);
199     }
200
201     @Test(expected = AuthenticationException.class)
202     public void doGetAuthenticationInfoInvalidURL() throws Exception {
203         UsernamePasswordToken token = new UsernamePasswordToken("user@sdn", "password");
204         final String invalidUrl = "not_an_url";
205         keystoneAuthRealm.setUrl(invalidUrl);
206         keystoneAuthRealm.doGetAuthenticationInfo(token, client);
207     }
208
209     @Test(expected = AuthenticationException.class)
210     public void doGetAuthenticationInfoUnknownTokenType() throws Exception {
211         AuthenticationToken token = new AuthenticationToken() {
212             @Override
213             public Object getPrincipal() {
214                 return null;
215             }
216
217             @Override
218             public Object getCredentials() {
219                 return null;
220             }
221         };
222         keystoneAuthRealm.doGetAuthenticationInfo(token, client);
223     }
224
225     @Test(expected = AuthenticationException.class)
226     public void doGetAuthenticationInfoNullToken() throws Exception {
227         keystoneAuthRealm.doGetAuthenticationInfo(null, client);
228     }
229
230     @Test
231     public void getClientTrusted() {
232         keystoneAuthRealm.buildClient(true, certificateManager, clientBuilder);
233         verify(clientBuilder).hostnameVerifier(same(HttpsURLConnection.getDefaultHostnameVerifier()));
234         verify(clientBuilder).sslContext(same(sslContext));
235     }
236
237     @Test
238     public void getClientUnTrusted() {
239         keystoneAuthRealm.buildClient(false, certificateManager, clientBuilder);
240         verify(clientBuilder).hostnameVerifier(same(UntrustedSSL.getHostnameVerifier()));
241         verify(clientBuilder).sslContext(same(UntrustedSSL.getSSLContext()));
242     }
243
244 }