aboutsummaryrefslogtreecommitdiffstats
path: root/odl-aaa-moon/aaa-authn-store/src
diff options
context:
space:
mode:
Diffstat (limited to 'odl-aaa-moon/aaa-authn-store/src')
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java45
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java154
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties14
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml22
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/main/resources/tokens.cfg4
-rw-r--r--odl-aaa-moon/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java66
6 files changed, 305 insertions, 0 deletions
diff --git a/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java b/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java
new file mode 100644
index 00000000..f3299723
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/Activator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import java.util.Dictionary;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * An activator for the default datastore implementation of {@link TokenStore}.
+ *
+ * @author liemmn
+ */
+public class Activator extends DependencyActivatorBase {
+
+ private static final String TOKEN_PID = "org.opendaylight.aaa.tokens";
+
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws Exception {
+ DefaultTokenStore ts = new DefaultTokenStore();
+ manager.add(createComponent().setInterface(new String[] { TokenStore.class.getName() },
+ null).setImplementation(ts));
+ context.registerService(ManagedService.class.getName(), ts,
+ addPid(DefaultTokenStore.defaults));
+ }
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+ }
+
+ private Dictionary<String, ?> addPid(Dictionary<String, String> dict) {
+ dict.put(Constants.SERVICE_PID, TOKEN_PID);
+ return dict;
+ }
+}
diff --git a/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java b/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java
new file mode 100644
index 00000000..df65be32
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/main/java/org/opendaylight/aaa/store/DefaultTokenStore.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.management.MBeanServer;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.management.ManagementService;
+import org.apache.felix.dm.Component;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenStore;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A default token store for STS.
+ *
+ * @author liemmn
+ *
+ */
+public class DefaultTokenStore implements TokenStore, ManagedService {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenStore.class);
+ private static final String TOKEN_STORE_CONFIG_ERR = "Token store configuration error";
+
+ private static final String TOKEN_CACHE_MANAGER = "org.opendaylight.aaa";
+ private static final String TOKEN_CACHE = "tokens";
+ private static final String EHCACHE_XML = "etc/ehcache.xml";
+
+ static final String MAX_CACHED_MEMORY = "maxCachedTokensInMemory";
+ static final String MAX_CACHED_DISK = "maxCachedTokensOnDisk";
+ static final String SECS_TO_LIVE = "secondsToLive";
+ static final String SECS_TO_IDLE = "secondsToIdle";
+
+ // Defaults (needed only for non-Karaf deployments)
+ static final Dictionary<String, String> defaults = new Hashtable<>();
+ static {
+ defaults.put(MAX_CACHED_MEMORY, Long.toString(10000));
+ defaults.put(MAX_CACHED_DISK, Long.toString(1000000));
+ defaults.put(SECS_TO_IDLE, Long.toString(3600));
+ defaults.put(SECS_TO_LIVE, Long.toString(3600));
+ }
+
+ // Token cache lock
+ private static final ReentrantLock cacheLock = new ReentrantLock();
+
+ // Token cache
+ private Cache tokens;
+
+ // This should be a singleton
+ DefaultTokenStore() {
+ }
+
+ // Called by DM when all required dependencies are satisfied.
+ void init(Component c) {
+ File ehcache = new File(EHCACHE_XML);
+ CacheManager cm;
+ if (ehcache.exists()) {
+ cm = CacheManager.create(ehcache.getAbsolutePath());
+ tokens = cm.getCache(TOKEN_CACHE);
+ LOG.info("Initialized token store with custom cache config");
+ } else {
+ cm = CacheManager.getInstance();
+ tokens = new Cache(
+ new CacheConfiguration(TOKEN_CACHE,
+ Integer.parseInt(defaults.get(MAX_CACHED_MEMORY))).maxEntriesLocalDisk(
+ Integer.parseInt(defaults.get(MAX_CACHED_DISK)))
+ .timeToLiveSeconds(
+ Long.parseLong(defaults.get(SECS_TO_LIVE)))
+ .timeToIdleSeconds(
+ Long.parseLong(defaults.get(SECS_TO_IDLE))));
+ cm.addCache(tokens);
+ LOG.info("Initialized token store with default cache config");
+ }
+ cm.setName(TOKEN_CACHE_MANAGER);
+
+ // JMX for cache management
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ ManagementService.registerMBeans(cm, mBeanServer, false, false, false, true);
+ }
+
+ // Called on shutdown
+ void destroy() {
+ LOG.info("Shutting down token store...");
+ CacheManager.getInstance().shutdown();
+ }
+
+ @Override
+ public Authentication get(String token) {
+ Element elem = tokens.get(token);
+ return (Authentication) ((elem != null) ? elem.getObjectValue() : null);
+ }
+
+ @Override
+ public void put(String token, Authentication auth) {
+ tokens.put(new Element(token, auth));
+ }
+
+ @Override
+ public boolean delete(String token) {
+ return tokens.remove(token);
+ }
+
+ @Override
+ public long tokenExpiration() {
+ return tokens.getCacheConfiguration().getTimeToLiveSeconds();
+ }
+
+ @Override
+ public void updated(@SuppressWarnings("rawtypes") Dictionary props)
+ throws ConfigurationException {
+ LOG.info("Updating token store configuration...");
+ if (props == null) {
+ // Someone deleted the configuration, use defaults
+ props = defaults;
+ }
+ reconfig(props);
+ }
+
+ // Refresh cache configuration...
+ private void reconfig(@SuppressWarnings("rawtypes") Dictionary props)
+ throws ConfigurationException {
+ cacheLock.lock();
+ try {
+ long secsToIdle = Long.parseLong(props.get(SECS_TO_IDLE).toString());
+ long secsToLive = Long.parseLong(props.get(SECS_TO_LIVE).toString());
+ int maxMem = Integer.parseInt(props.get(MAX_CACHED_MEMORY).toString());
+ int maxDisk = Integer.parseInt(props.get(MAX_CACHED_DISK).toString());
+ CacheConfiguration config = tokens.getCacheConfiguration();
+ config.setTimeToIdleSeconds(secsToIdle);
+ config.setTimeToLiveSeconds(secsToLive);
+ config.maxEntriesLocalHeap(maxMem);
+ config.maxEntriesLocalDisk(maxDisk);
+ } catch (Throwable t) {
+ throw new ConfigurationException(null, TOKEN_STORE_CONFIG_ERR, t);
+ } finally {
+ cacheLock.unlock();
+ }
+ }
+}
diff --git a/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties b/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 00000000..b88d5c10
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,14 @@
+org.opendaylight.aaa.tokens.name = Opendaylight AAA Token Configuration
+org.opendaylight.aaa.tokens.description = Configuration for AAA tokens
+org.opendaylight.aaa.tokens.maxCachedTokensInMemory.name = Memory Configuration
+org.opendaylight.aaa.tokens.maxCachedTokensInMemory.description = Maximum number of \
+tokens in memory
+org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.name = Disk Configuration
+org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.description = Maximum number of \
+tokens in memory
+org.opendaylight.aaa.tokens.secondsToLive.name = Token Expiration
+org.opendaylight.aaa.tokens.secondsToLive.description = Maximum number of \
+seconds a token can exist regardless of use. Zero (0) means never expires.
+org.opendaylight.aaa.tokens.secondsToIdle.name = Unused Token Expiration
+org.opendaylight.aaa.tokens.secondsToIdle.description = Maximum number of \
+seconds a token can exist without being accessed. Zero (0) means never expires. \ No newline at end of file
diff --git a/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml b/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml
new file mode 100644
index 00000000..d04874f4
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
+ localization="OSGI-INF/metatype/metatype">
+ <OCD id="org.opendaylight.aaa.tokens" name="%org.opendaylight.aaa.tokens.name"
+ description="%org.opendaylight.aaa.tokens.description">
+ <AD id="maxCachedTokensInMemory" type="Long" default="10000"
+ name="%org.opendaylight.aaa.tokens.maxCachedTokensInMemory.name"
+ description="%org.opendaylight.aaa.tokens.maxCachedTokensInMemory.description" />
+ <AD id="maxCachedTokensOnDisk" type="Long" default="1000000"
+ name="%org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.name"
+ description="%org.opendaylight.aaa.tokens.maxCachedTokensOnDisk.description" />
+ <AD id="secondsToLive" type="Long" default="3600"
+ name="%org.opendaylight.aaa.tokens.secondsToLive.name"
+ description="%org.opendaylight.aaa.tokens.secondsToLive.description" />
+ <AD id="secondsToIdle" type="Long" default="3600"
+ name="%org.opendaylight.aaa.tokens.secondsToIdle.name"
+ description="%org.opendaylight.aaa.tokens.secondsToIdle.description" />
+ </OCD>
+ <Designate pid="org.opendaylight.aaa.tokens">
+ <Object ocdref="org.opendaylight.aaa.tokens" />
+ </Designate>
+</metatype:MetaData> \ No newline at end of file
diff --git a/odl-aaa-moon/aaa-authn-store/src/main/resources/tokens.cfg b/odl-aaa-moon/aaa-authn-store/src/main/resources/tokens.cfg
new file mode 100644
index 00000000..d3dda90e
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/main/resources/tokens.cfg
@@ -0,0 +1,4 @@
+maxCachedTokensInMemory=10000
+maxCachedTokensOnDisk=1000000
+secondsToLive=3600
+secondsToIdle=3600 \ No newline at end of file
diff --git a/odl-aaa-moon/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java b/odl-aaa-moon/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java
new file mode 100644
index 00000000..e5c837bf
--- /dev/null
+++ b/odl-aaa-moon/aaa-authn-store/src/test/java/org/opendaylight/aaa/store/DefaultTokenStoreTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.store;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.aaa.store.DefaultTokenStore.MAX_CACHED_DISK;
+import static org.opendaylight.aaa.store.DefaultTokenStore.MAX_CACHED_MEMORY;
+import static org.opendaylight.aaa.store.DefaultTokenStore.SECS_TO_IDLE;
+import static org.opendaylight.aaa.store.DefaultTokenStore.SECS_TO_LIVE;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import org.apache.felix.dm.Component;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.aaa.AuthenticationBuilder;
+import org.opendaylight.aaa.ClaimBuilder;
+import org.opendaylight.aaa.api.Authentication;
+import org.osgi.service.cm.ConfigurationException;
+
+public class DefaultTokenStoreTest {
+ private static final String FOO_TOKEN = "foo_token";
+ private final DefaultTokenStore dts = new DefaultTokenStore();
+ private static final Dictionary<String, String> config = new Hashtable<>();
+ static {
+ config.put(MAX_CACHED_MEMORY, Long.toString(3));
+ config.put(MAX_CACHED_DISK, Long.toString(3));
+ config.put(SECS_TO_IDLE, Long.toString(1));
+ config.put(SECS_TO_LIVE, Long.toString(1));
+ }
+
+ @Before
+ public void setup() throws ConfigurationException {
+ dts.init(mock(Component.class));
+ dts.updated(config);
+ }
+
+ @After
+ public void teardown() {
+ dts.destroy();
+ }
+
+ @Test
+ public void testCache() throws InterruptedException {
+ Authentication auth = new AuthenticationBuilder(new ClaimBuilder().setUser("foo")
+ .setUserId("1234")
+ .addRole("admin").build()).build();
+ dts.put(FOO_TOKEN, auth);
+ assertEquals(auth, dts.get(FOO_TOKEN));
+ dts.delete(FOO_TOKEN);
+ assertNull(dts.get(FOO_TOKEN));
+ dts.put(FOO_TOKEN, auth);
+ Thread.sleep(1200);
+ assertNull(dts.get(FOO_TOKEN));
+ }
+
+}