2 * Copyright (c) 2015 Cisco Systems, 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.authn.mdsal.store;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.math.BigInteger;
16 import java.util.concurrent.ExecutorService;
17 import java.util.concurrent.Executors;
18 import org.opendaylight.aaa.api.Authentication;
19 import org.opendaylight.aaa.api.TokenStore;
20 import org.opendaylight.aaa.authn.mdsal.store.util.AuthNStoreUtil;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
27 import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.TokenCacheTimes;
28 import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenList;
29 import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.TokenListKey;
30 import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.token_cache_times.token_list.UserTokens;
31 import org.opendaylight.yang.gen.v1.urn.aaa.yang.authn.claims.rev141029.tokencache.Claims;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public class AuthNStore implements AutoCloseable, TokenStore {
38 private static final Logger LOG = LoggerFactory.getLogger(AuthNStore.class);
39 private DataBroker broker;
40 private static BigInteger timeToLive;
41 private static Integer timeToWait;
42 private final ExecutorService deleteExpiredTokenThread = Executors.newFixedThreadPool(1);
43 private final DataEncrypter dataEncrypter;
45 public AuthNStore(final DataBroker dataBroker, final String config_key) {
46 this.broker = dataBroker;
47 this.dataEncrypter = new DataEncrypter(config_key);
48 LOG.info("Created MD-SAL AAA Token Cache Service...");
52 public void close() throws Exception {
53 deleteExpiredTokenThread.shutdown();
54 LOG.info("MD-SAL AAA Token Cache closed...");
59 public void put(String token, Authentication auth) {
60 token = dataEncrypter.encrypt(token);
61 Claims claims = AuthNStoreUtil.createClaimsRecord(token, auth);
63 // create and insert parallel struct
64 UserTokens userTokens = AuthNStoreUtil.createUserTokens(token, timeToLive.longValue());
65 TokenList tokenlist = AuthNStoreUtil.createTokenList(userTokens, auth.userId());
67 writeClaimAndTokenToStore(claims, userTokens, tokenlist);
68 deleteExpiredTokenThread.execute(deleteOldTokens(claims));
72 public Authentication get(String token) {
73 token = dataEncrypter.encrypt(token);
74 Authentication authentication = null;
75 Claims claims = readClaims(token);
77 UserTokens userToken = readUserTokensFromDS(claims.getToken(), claims.getUserId());
78 authentication = AuthNStoreUtil.convertClaimToAuthentication(claims,
79 userToken.getExpiration());
81 deleteExpiredTokenThread.execute(deleteOldTokens(claims));
82 return authentication;
86 public boolean delete(String token) {
87 token = dataEncrypter.encrypt(token);
88 boolean result = false;
89 Claims claims = readClaims(token);
90 result = deleteClaims(token);
92 deleteUserTokenFromDS(token, claims.getUserId());
94 deleteExpiredTokenThread.execute(deleteOldTokens(claims));
99 public long tokenExpiration() {
100 return timeToLive.longValue();
103 public void setTimeToLive(BigInteger timeToLive) {
104 this.timeToLive = timeToLive;
107 public void setTimeToWait(Integer timeToWait) {
108 this.timeToWait = timeToWait;
111 private void writeClaimAndTokenToStore(final Claims claims, UserTokens usertokens,
112 final TokenList tokenlist) {
114 final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(claims.getToken());
115 WriteTransaction tx = broker.newWriteOnlyTransaction();
116 tx.put(LogicalDatastoreType.OPERATIONAL, claims_iid, claims, true);
118 final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
119 tokenlist.getUserId(), usertokens.getTokenid());
120 tx.put(LogicalDatastoreType.OPERATIONAL, userTokens_iid, usertokens, true);
122 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
123 Futures.addCallback(commitFuture, new FutureCallback<Void>() {
126 public void onSuccess(Void result) {
127 LOG.trace("Token {} was written to datastore.", claims.getToken());
128 LOG.trace("Tokenlist for userId {} was written to datastore.",
129 tokenlist.getUserId());
133 public void onFailure(Throwable t) {
134 LOG.error("Inserting token {} to datastore failed.", claims.getToken());
135 LOG.trace("Inserting for userId {} tokenlist to datastore failed.",
136 tokenlist.getUserId());
142 private Claims readClaims(String token) {
143 final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(token);
144 Claims claims = null;
145 ReadTransaction rt = broker.newReadOnlyTransaction();
146 CheckedFuture<Optional<Claims>, ReadFailedException> claimsFuture = rt.read(
147 LogicalDatastoreType.OPERATIONAL, claims_iid);
149 Optional<Claims> maybeClaims = claimsFuture.checkedGet();
150 if (maybeClaims.isPresent()) {
151 claims = maybeClaims.get();
153 } catch (ReadFailedException e) {
155 "Something wrong happened in DataStore. Getting Claim for token {} failed.",
161 private TokenList readTokenListFromDS(String userId) {
162 InstanceIdentifier<TokenList> tokenList_iid = InstanceIdentifier.builder(
163 TokenCacheTimes.class).child(TokenList.class, new TokenListKey(userId)).build();
164 TokenList tokenList = null;
165 ReadTransaction rt = broker.newReadOnlyTransaction();
166 CheckedFuture<Optional<TokenList>, ReadFailedException> userTokenListFuture = rt.read(
167 LogicalDatastoreType.OPERATIONAL, tokenList_iid);
169 Optional<TokenList> maybeTokenList = userTokenListFuture.checkedGet();
170 if (maybeTokenList.isPresent()) {
171 tokenList = maybeTokenList.get();
173 } catch (ReadFailedException e) {
175 "Something wrong happened in DataStore. Getting TokenList for userId {} failed.",
181 private UserTokens readUserTokensFromDS(String token, String userId) {
182 final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
184 UserTokens userTokens = null;
186 ReadTransaction rt = broker.newReadOnlyTransaction();
187 CheckedFuture<Optional<UserTokens>, ReadFailedException> userTokensFuture = rt.read(
188 LogicalDatastoreType.OPERATIONAL, userTokens_iid);
191 Optional<UserTokens> maybeUserTokens = userTokensFuture.checkedGet();
192 if (maybeUserTokens.isPresent()) {
193 userTokens = maybeUserTokens.get();
195 } catch (ReadFailedException e) {
197 "Something wrong happened in DataStore. Getting UserTokens for token {} failed.",
204 private boolean deleteClaims(String token) {
205 final InstanceIdentifier<Claims> claims_iid = AuthNStoreUtil.createInstIdentifierForTokencache(token);
206 boolean result = false;
207 WriteTransaction tx = broker.newWriteOnlyTransaction();
208 tx.delete(LogicalDatastoreType.OPERATIONAL, claims_iid);
209 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
212 commitFuture.checkedGet();
214 } catch (TransactionCommitFailedException e) {
215 LOG.error("Something wrong happened in DataStore. Claim "
216 + "deletion for token {} from DataStore failed.", token, e);
221 private void deleteUserTokenFromDS(String token, String userId) {
222 final InstanceIdentifier<UserTokens> userTokens_iid = AuthNStoreUtil.createInstIdentifierUserTokens(
225 WriteTransaction tx = broker.newWriteOnlyTransaction();
226 tx.delete(LogicalDatastoreType.OPERATIONAL, userTokens_iid);
227 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = tx.submit();
229 commitFuture.checkedGet();
230 } catch (TransactionCommitFailedException e) {
231 LOG.error("Something wrong happened in DataStore. UserToken "
232 + "deletion for token {} from DataStore failed.", token, e);
236 private Runnable deleteOldTokens(final Claims claims) {
237 return new Runnable() {
241 TokenList tokenList = null;
242 if (claims != null) {
243 tokenList = readTokenListFromDS(claims.getUserId());
245 if (tokenList != null) {
246 for (UserTokens currUserToken : tokenList.getUserTokens()) {
247 long diff = System.currentTimeMillis()
248 - currUserToken.getTimestamp().longValue();
249 if (diff > currUserToken.getExpiration()
250 && currUserToken.getExpiration() != 0) {
251 if (deleteClaims(currUserToken.getTokenid())) {
252 deleteUserTokenFromDS(currUserToken.getTokenid(),
254 LOG.trace("Expired tokens for UserId {} deleted.",