67ad6ebc572475dce506bc4aee96bdbf6b00254d
[netconf.git] / netconf / aaa-authn-odl-plugin / src / main / java / org / opendaylight / aaa / odl / CredentialServiceAuthProvider.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, 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 package org.opendaylight.aaa.odl;
9
10 import java.util.Map;
11 import org.opendaylight.aaa.api.AuthenticationException;
12 import org.opendaylight.aaa.api.Claim;
13 import org.opendaylight.aaa.api.CredentialAuth;
14 import org.opendaylight.aaa.api.PasswordCredentials;
15 import org.opendaylight.netconf.auth.AuthProvider;
16 import org.osgi.framework.BundleContext;
17 import org.osgi.framework.ServiceReference;
18 import org.osgi.util.tracker.ServiceTracker;
19 import org.osgi.util.tracker.ServiceTrackerCustomizer;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23
24 /**
25  * AuthProvider implementation delegating to AAA CredentialAuth<PasswordCredentials> instance.
26  */
27 public final class CredentialServiceAuthProvider implements AuthProvider, AutoCloseable {
28     private static final Logger logger = LoggerFactory.getLogger(CredentialServiceAuthProvider.class);
29
30     /**
31      * Singleton instance with delayed instantiation
32      */
33     public static volatile Map.Entry<BundleContext, CredentialServiceAuthProvider> INSTANCE;
34
35     // FIXME CredentialAuth is generic and it causes warnings during compilation
36     // Maybe there should be a PasswordCredentialAuth implements CredentialAuth<PasswordCredentials>
37     private volatile CredentialAuth<PasswordCredentials> nullableCredService;
38     private final ServiceTracker<CredentialAuth, CredentialAuth> listenerTracker;
39
40     public CredentialServiceAuthProvider(final BundleContext bundleContext) {
41
42         final ServiceTrackerCustomizer<CredentialAuth, CredentialAuth> customizer = new ServiceTrackerCustomizer<CredentialAuth, CredentialAuth>() {
43             @Override
44             public CredentialAuth addingService(final ServiceReference<CredentialAuth> reference) {
45                 logger.trace("Credential service {} added", reference);
46                 nullableCredService = bundleContext.getService(reference);
47                 return nullableCredService;
48             }
49
50             @Override
51             public void modifiedService(final ServiceReference<CredentialAuth> reference, final CredentialAuth service) {
52                 logger.trace("Replacing modified Credential service {}", reference);
53                 nullableCredService = service;
54             }
55
56             @Override
57             public void removedService(final ServiceReference<CredentialAuth> reference, final CredentialAuth service) {
58                 logger.trace("Removing Credential service {}. This AuthProvider will fail to authenticate every time", reference);
59                 synchronized (CredentialServiceAuthProvider.this) {
60                     nullableCredService = null;
61                 }
62             }
63         };
64         listenerTracker = new ServiceTracker<>(bundleContext, CredentialAuth.class, customizer);
65         listenerTracker.open();
66     }
67
68     /**
69      * Authenticate user. This implementation tracks CredentialAuth&lt;PasswordCredentials&gt; and delegates the decision to it. If the service is not
70      * available, IllegalStateException is thrown.
71      */
72     @Override
73     public synchronized boolean authenticated(final String username, final String password) {
74         if (nullableCredService == null) {
75             logger.warn("Cannot authenticate user '{}', Credential service is missing", username);
76             throw new IllegalStateException("Credential service is not available");
77         }
78
79         Claim claim;
80         try {
81             claim = nullableCredService.authenticate(new PasswordCredentialsWrapper(username, password));
82         } catch (AuthenticationException e) {
83             logger.debug("Authentication failed for user '{}' : {}", username, e);
84             return false;
85         }
86
87         logger.debug("Authentication result for user '{}' : {}", username, claim.domain());
88         return true;
89     }
90
91     /**
92      * Invoke by blueprint
93      */
94     @Override
95     public void close() {
96         listenerTracker.close();
97         nullableCredService = null;
98     }
99
100     private static final class PasswordCredentialsWrapper implements PasswordCredentials {
101         private final String username;
102         private final String password;
103
104         public PasswordCredentialsWrapper(final String username, final String password) {
105             this.username = username;
106             this.password = password;
107         }
108
109         @Override
110         public String username() {
111             return username;
112         }
113
114         @Override
115         public String password() {
116             return password;
117         }
118
119         @Override
120         public String domain() {
121             // If this is left null, default "sdn" domain is assumed
122             return null;
123         }
124     }
125 }