2 * Copyright (c) 2017 Ericsson Inc. and others. All rights reserved.
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
9 package org.opendaylight.aaa.shiro.realm;
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;
22 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
23 import java.net.MalformedURLException;
24 import java.net.URISyntaxException;
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;
56 @RunWith(MockitoJUnitRunner.class)
57 public class KeystoneAuthRealmTest {
60 private SimpleHttpRequest.Builder<KeystoneToken> builder;
63 private ICertificateManager certificateManager;
66 private SSLContext sslContext;
69 private SimpleHttpRequest.Builder<KeystoneToken> requestBuilder;
72 private SimpleHttpRequest<KeystoneToken> httpRequest;
75 private SimpleHttpClient.Builder clientBuilder;
78 private SimpleHttpClient client;
81 private KeystoneToken response;
84 private ArgumentCaptor<KeystoneAuth> keystoneAuthArgumentCaptor;
87 private KeystoneAuthRealm keystoneAuthRealm;
89 private KeystoneToken.Token ksToken;
92 public void setup() throws MalformedURLException, URISyntaxException {
93 AAAShiroProvider.newInstance(null, null, null, null, mock(HttpService.class), null, null, null, null, null);
95 final String testUrl = "http://example.com";
96 // a token for a user without roles
97 ksToken = new KeystoneToken.Token();
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);
116 keystoneAuthRealm.setUrl(testUrl);
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(),
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"));
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());
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);
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());
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(),
174 assertThat(info, notNullValue());
175 ODLPrincipal principal = (ODLPrincipal) info.getPrincipals().getPrimaryPrincipal();
176 assertThat(principal.getUserId(), is("user@sdn"));
177 assertThat(principal.getDomain(), is("sdn"));
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(),
188 assertThat(info, notNullValue());
189 ODLPrincipal principal = (ODLPrincipal) info.getPrincipals().getPrimaryPrincipal();
190 assertThat(principal.getUserId(), is("user@sdn"));
191 assertThat(principal.getDomain(), is("sdn"));
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);
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);
209 @Test(expected = AuthenticationException.class)
210 public void doGetAuthenticationInfoUnknownTokenType() throws Exception {
211 AuthenticationToken token = new AuthenticationToken() {
213 public Object getPrincipal() {
218 public Object getCredentials() {
222 keystoneAuthRealm.doGetAuthenticationInfo(token, client);
225 @Test(expected = AuthenticationException.class)
226 public void doGetAuthenticationInfoNullToken() throws Exception {
227 keystoneAuthRealm.doGetAuthenticationInfo(null, client);
231 public void getClientTrusted() {
232 keystoneAuthRealm.buildClient(true, certificateManager, clientBuilder);
233 verify(clientBuilder).hostnameVerifier(same(HttpsURLConnection.getDefaultHostnameVerifier()));
234 verify(clientBuilder).sslContext(same(sslContext));
238 public void getClientUnTrusted() {
239 keystoneAuthRealm.buildClient(false, certificateManager, clientBuilder);
240 verify(clientBuilder).hostnameVerifier(same(UntrustedSSL.getHostnameVerifier()));
241 verify(clientBuilder).sslContext(same(UntrustedSSL.getSSLContext()));