You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2017/06/19 19:58:39 UTC

[1/7] usergrid git commit: Initial commit of new token module to replace Hector for access token storage.

Repository: usergrid
Updated Branches:
  refs/heads/master d8a7e10ca -> 375814e00


Initial commit of new token module to replace Hector for access token storage.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/179f12db
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/179f12db
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/179f12db

Branch: refs/heads/master
Commit: 179f12db0ef55cf9c28936678a933e2de04034eb
Parents: 3f819dc
Author: Michael Russo <ru...@google.com>
Authored: Fri Jun 16 00:15:14 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Fri Jun 16 00:15:14 2017 -0700

----------------------------------------------------------------------
 stack/corepersistence/pom.xml                   |   1 +
 stack/corepersistence/token/pom.xml             |  70 +++
 .../persistence/token/guice/TokenModule.java    |  48 ++
 .../token/impl/TokenSerialization.java          |  50 ++
 .../token/impl/TokenSerializationImpl.java      | 536 +++++++++++++++++++
 .../persistence/token/TokenTestModule.java      |  40 ++
 .../token/src/test/resources/log4j.properties   |  38 ++
 7 files changed, 783 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/pom.xml b/stack/corepersistence/pom.xml
index 8a45323..45aad4b 100644
--- a/stack/corepersistence/pom.xml
+++ b/stack/corepersistence/pom.xml
@@ -113,6 +113,7 @@ limitations under the License.
         <module>queue</module>
         <module>cache</module>
         <module>actorsystem</module>
+        <module>token</module>
     </modules>
 
     <build>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/pom.xml b/stack/corepersistence/token/pom.xml
new file mode 100644
index 0000000..fcbd73c
--- /dev/null
+++ b/stack/corepersistence/token/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>persistence</artifactId>
+        <groupId>org.apache.usergrid</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <description>The module for handling access token persistence</description>
+
+    <artifactId>token</artifactId>
+    <name>Usergrid Token</name>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons.lang.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.usergrid</groupId>
+            <artifactId>common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- test deps -->
+
+        <dependency>
+            <groupId>org.apache.usergrid</groupId>
+            <artifactId>common</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+        <!--
+        <dependency>
+            <groupId>org.apache.usergrid</groupId>
+            <artifactId>collection</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        -->
+
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
new file mode 100644
index 0000000..13d6b43
--- /dev/null
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.token.guice;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Key;
+import com.google.inject.multibindings.Multibinder;
+import org.apache.usergrid.persistence.cache.CacheFactory;
+import org.apache.usergrid.persistence.cache.impl.CacheFactoryImpl;
+import org.apache.usergrid.persistence.cache.impl.TokenSerialization;
+import org.apache.usergrid.persistence.cache.impl.TokenSerializationImpl;
+import org.apache.usergrid.persistence.core.migration.schema.Migration;
+
+
+/**
+ * Wire up cache impl.
+ */
+public class TokenModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+
+        bind( CacheFactory.class ).to( CacheFactoryImpl.class );
+
+        bind( TokenSerialization.class ).to( TokenSerializationImpl.class );
+
+        Multibinder<Migration> migrationBinding = Multibinder.newSetBinder( binder(), Migration.class );
+        migrationBinding.addBinding().to(Key.get(TokenSerialization.class));
+
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
new file mode 100644
index 0000000..bf9337f
--- /dev/null
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.persistence.token.impl;
+
+
+import org.apache.usergrid.persistence.core.migration.schema.Migration;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+
+/**
+ * Serialize token information to/from Cassandra. This was ported over to use a newer cassandra client from the old
+ * persistence code @
+ *
+ *     https://github.com/apache/usergrid/tree/3f819dc0679f84edb57c52e69b58622417cfd59f
+ *     org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl
+ *
+ */
+public interface TokenSerialization extends Migration {
+
+    void deleteToken(UUID tokenUUID);
+
+    void revokeToken(UUID tokenUUID, ByteBuffer principalKeyBuffer);
+
+    void updateTokenAccessTime(UUID tokenUUID, int accessdTime, int inactiveTime );
+
+    Map<String, Object> getTokenInfo(UUID tokenUUID);
+
+    void putTokenInfo(UUID tokenUUID, Map<String, Object> tokenInfo);
+
+    List<UUID> getTokensForPrincipal(ByteBuffer principalKeyBuffer);
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
new file mode 100644
index 0000000..b07472d
--- /dev/null
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
@@ -0,0 +1,536 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.persistence.token.impl;
+
+import com.datastax.driver.core.*;
+import com.datastax.driver.core.querybuilder.Clause;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.smile.SmileFactory;
+import com.google.common.base.Preconditions;
+import com.google.common.hash.Funnel;
+import com.google.inject.Inject;
+import org.apache.usergrid.persistence.core.CassandraConfig;
+import org.apache.usergrid.persistence.core.astyanax.*;
+import org.apache.usergrid.persistence.core.datastax.CQLUtils;
+import org.apache.usergrid.persistence.core.datastax.TableDefinition;
+import org.apache.usergrid.persistence.core.datastax.impl.TableDefinitionImpl;
+import org.apache.usergrid.persistence.core.shard.ExpandingShardLocator;
+import org.apache.usergrid.persistence.core.shard.StringHashUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+
+/**
+ * Serialize cache to Cassandra.
+ */
+public class TokenSerializationImpl implements TokenSerialization {
+
+    public static final Logger logger = LoggerFactory.getLogger(TokenSerializationImpl.class);
+
+    private SmileFactory smile = new SmileFactory();
+
+    private ObjectMapper smileMapper = new ObjectMapper( smile );
+
+    private static final String TOKEN_UUID = "uuid";
+    private static final String TOKEN_TYPE = "type";
+    private static final String TOKEN_CREATED = "created";
+    private static final String TOKEN_ACCESSED = "accessed";
+    private static final String TOKEN_INACTIVE = "inactive";
+    private static final String TOKEN_DURATION = "duration";
+    private static final String TOKEN_PRINCIPAL_TYPE = "principal";
+    private static final String TOKEN_ENTITY = "entity";
+    private static final String TOKEN_APPLICATION = "application";
+    private static final String TOKEN_STATE = "state";
+    private static final String TOKEN_WORKFLOW_ORG_ID = "workflowOrgId";
+
+    private static final Set<String> TOKEN_PROPERTIES;
+
+    static {
+        HashSet<String> set = new HashSet<String>();
+        set.add( TOKEN_UUID );
+        set.add( TOKEN_TYPE );
+        set.add( TOKEN_CREATED );
+        set.add( TOKEN_ACCESSED );
+        set.add( TOKEN_INACTIVE );
+        set.add( TOKEN_PRINCIPAL_TYPE );
+        set.add( TOKEN_ENTITY );
+        set.add( TOKEN_APPLICATION );
+        set.add( TOKEN_STATE );
+        set.add( TOKEN_DURATION );
+        set.add( TOKEN_WORKFLOW_ORG_ID );
+        TOKEN_PROPERTIES = Collections.unmodifiableSet(set);
+    }
+
+    private static final HashSet<String> REQUIRED_TOKEN_PROPERTIES = new HashSet<String>();
+
+
+    static {
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_UUID );
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_TYPE );
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_CREATED );
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_ACCESSED );
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_INACTIVE );
+        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_DURATION );
+    }
+
+
+
+    private static final String TOKENS_TABLE = CQLUtils.quote("Tokens");
+    private static final Collection<String> TOKENS_PARTITION_KEYS = Collections.singletonList("key");
+    private static final Collection<String> TOKENS_COLUMN_KEYS = Collections.singletonList("column1");
+    private static final Map<String, DataType.Name> TOKENS_COLUMNS =
+        new HashMap<String, DataType.Name>() {{
+            put( "key", DataType.Name.BLOB );
+            put( "column1", DataType.Name.BLOB );
+            put( "value", DataType.Name.BLOB ); }};
+    private static final Map<String, String> TOKENS_CLUSTERING_ORDER =
+        new HashMap<String, String>(){{ put( "column1", "ASC" ); }};
+
+    private static final String PRINCIPAL_TOKENS_TABLE = CQLUtils.quote("PrincipalTokens");
+    private static final Collection<String> PRINCIPAL_TOKENS_PARTITION_KEYS = Collections.singletonList("key");
+    private static final Collection<String> PRINCIPAL_TOKENS_COLUMN_KEYS = Collections.singletonList("column1");
+    private static final Map<String, DataType.Name> PRINCIPAL_TOKENS_COLUMNS =
+        new HashMap<String, DataType.Name>() {{
+            put( "key", DataType.Name.BLOB );
+            put( "column1", DataType.Name.UUID );
+            put( "value", DataType.Name.BLOB ); }};
+    private static final Map<String, String> PRINCIPAL_TOKENS_CLUSTERING_ORDER =
+        new HashMap<String, String>(){{ put( "column1", "ASC" ); }};
+
+
+
+
+    private final Session session;
+    private final CassandraConfig cassandraConfig;
+
+
+
+
+    @Inject
+    public TokenSerializationImpl(final Session session,
+                                  final CassandraConfig cassandraConfig ) {
+        this.session = session;
+        this.cassandraConfig = cassandraConfig;
+
+    }
+
+
+    @Override
+    public void deleteToken(UUID tokenUUID){
+
+    }
+
+    @Override
+    public void revokeToken(UUID tokenUUID, ByteBuffer principalKeyBuffer){
+
+    }
+
+    @Override
+    public void updateTokenAccessTime(UUID tokenUUID, int accessdTime, int inactiveTime ){
+
+    }
+
+    @Override
+    public Map<String, Object> getTokenInfo(UUID tokenUUID){
+
+        Preconditions.checkNotNull(tokenUUID, "token UUID is required");
+
+        List<ByteBuffer> tokenProperties = new ArrayList<>();
+        TOKEN_PROPERTIES.forEach( prop ->
+            tokenProperties.add(DataType.serializeValue(prop, ProtocolVersion.NEWEST_SUPPORTED)));
+
+        final ByteBuffer key = DataType.text().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED);
+
+        final Clause inKey = QueryBuilder.eq("key", key);
+        final Clause inColumn = QueryBuilder.in("column1", tokenProperties );
+
+        final Statement statement = QueryBuilder.select().all().from(TOKENS_TABLE)
+            .where(inKey)
+            .and(inColumn)
+            .setConsistencyLevel(cassandraConfig.getDataStaxReadCl());
+
+        final ResultSet resultSet = session.execute(statement);
+        final List<Row> rows = resultSet.all();
+
+        Map<String, Object> tokenInfo = new HashMap<>();
+
+        rows.forEach( row -> {
+
+            final String name = row.getString("column1");
+            final Object value = deserializeColumnValue(name, row.getBytes("value"));
+
+            if (value == null){
+                throw new RuntimeException("error deserializing token info for property: "+name);
+            }
+
+            tokenInfo.put(name, value);
+
+        });
+
+        return tokenInfo;
+    }
+
+    @Override
+    public void putTokenInfo(UUID tokenUUID, Map<String, Object> tokenInfo){
+
+    }
+
+    @Override
+    public List<UUID> getTokensForPrincipal(ByteBuffer principalKeyBuffer){
+        return new ArrayList<>();
+    }
+
+
+    private Object deserializeColumnValue(final String name, final ByteBuffer bb){
+
+
+        switch (name) {
+            case TOKEN_TYPE:
+            case TOKEN_PRINCIPAL_TYPE:
+                return DataType.text().deserialize(bb, ProtocolVersion.NEWEST_SUPPORTED);
+            case TOKEN_CREATED:
+            case TOKEN_ACCESSED:
+            case TOKEN_INACTIVE:
+            case TOKEN_DURATION:
+                return DataType.bigint().deserialize(bb, ProtocolVersion.NEWEST_SUPPORTED);
+            case TOKEN_ENTITY:
+            case TOKEN_APPLICATION:
+            case TOKEN_WORKFLOW_ORG_ID:
+            case TOKEN_UUID:
+                return DataType.uuid().deserialize(bb, ProtocolVersion.NEWEST_SUPPORTED);
+            case TOKEN_STATE:
+                fromByteBuffer(bb, Object.class);
+        }
+
+        return null;
+    }
+
+
+    private Object fromByteBuffer( ByteBuffer byteBuffer, Class<?> clazz ) {
+        if ( ( byteBuffer == null ) || !byteBuffer.hasRemaining() ) {
+            return null;
+        }
+        if ( clazz == null ) {
+            clazz = Object.class;
+        }
+
+        Object obj = null;
+        try {
+            obj = smileMapper.readValue( byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
+                byteBuffer.remaining(), clazz );
+        }
+        catch ( Exception e ) {
+            logger.error( "Error parsing SMILE bytes", e );
+        }
+        return obj;
+    }
+
+//    @Override
+//    public V readValue(CacheScope scope, K key, TypeReference typeRef ) {
+//
+//        return readValueCQL( scope, key, typeRef);
+//
+//    }
+
+
+//    private V readValueCQL(CacheScope scope, K key, TypeReference typeRef){
+//
+//        Preconditions.checkNotNull(scope, "scope is required");
+//        Preconditions.checkNotNull(key, "key is required");
+//
+//        final String rowKeyString = scope.getApplication().getUuid().toString();
+//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
+//
+//        // determine column name based on K key to string
+//        final String columnName = key.toString();
+//
+//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
+//        final Clause inColumn = QueryBuilder.eq("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED) );
+//
+//        final Statement statement = QueryBuilder.select().all().from(TOKENS_TABLE)
+//            .where(inKey)
+//            .and(inColumn)
+//            .setConsistencyLevel(cassandraConfig.getDataStaxReadCl());
+//
+//        final ResultSet resultSet = session.execute(statement);
+//        final com.datastax.driver.core.Row row = resultSet.one();
+//
+//        if (row == null){
+//
+//            if(logger.isDebugEnabled()){
+//                logger.debug("Cache value not found for key {}", key );
+//            }
+//
+//            return null;
+//        }
+//
+//
+//        try {
+//
+//            return MAPPER.readValue(row.getBytes("value").array(), typeRef);
+//
+//        } catch (IOException ioe) {
+//            logger.error("Unable to read cached value", ioe);
+//            throw new RuntimeException("Unable to read cached value", ioe);
+//        }
+//
+//
+//    }
+
+
+//    @Override
+//    public V writeValue(CacheScope scope, K key, V value, Integer ttl) {
+//
+//        return writeValueCQL( scope, key, value, ttl);
+//
+//    }
+//
+//    private V writeValueCQL(CacheScope scope, K key, V value, Integer ttl) {
+//
+//        Preconditions.checkNotNull( scope, "scope is required");
+//        Preconditions.checkNotNull( key, "key is required" );
+//        Preconditions.checkNotNull( value, "value is required");
+//        Preconditions.checkNotNull( ttl, "ttl is required");
+//
+//
+//        final String rowKeyString = scope.getApplication().getUuid().toString();
+//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
+//
+//        // determine column name based on K key to string
+//        final String columnName = key.toString();
+//
+//        // serialize cache item
+//        byte[] cacheBytes;
+//        try {
+//            cacheBytes = MAPPER.writeValueAsBytes(value);
+//        } catch (JsonProcessingException jpe) {
+//            throw new RuntimeException("Unable to serialize cache value", jpe);
+//        }
+//
+//        final Using timeToLive = QueryBuilder.ttl(ttl);
+//
+//
+//        // convert to ByteBuffer for the blob DataType in Cassandra
+//        final ByteBuffer bb = ByteBuffer.allocate(cacheBytes.length);
+//        bb.put(cacheBytes);
+//        bb.flip();
+//
+//        final Statement cacheEntry = QueryBuilder.insertInto(TOKENS_TABLE)
+//            .using(timeToLive)
+//            .value("key", getPartitionKey(scope, rowKeyString, bucket))
+//            .value("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED))
+//            .value("value", bb);
+//
+//
+//        session.execute(cacheEntry);
+//
+//        logger.debug("Wrote cache item to scope {}\n   key/value types {}/{}\n   key:value: {}:{}",
+//            scope.getApplication().getUuid(),
+//            key.getClass().getSimpleName(),
+//            value.getClass().getSimpleName(),
+//            key,
+//            value);
+//
+//        return value;
+//
+//    }
+//
+//
+//
+//    @Override
+//    public void removeValue(CacheScope scope, K key) {
+//
+//        removeValueCQL(scope, key);
+//
+//    }
+//
+//
+//    private void removeValueCQL(CacheScope scope, K key) {
+//
+//        Preconditions.checkNotNull( scope, "scope is required");
+//        Preconditions.checkNotNull( key, "key is required" );
+//
+//        // determine bucketed row-key based application UUID
+//
+//        final String rowKeyString = scope.getApplication().getUuid().toString();
+//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
+//
+//        // determine column name based on K key to string
+//        final String columnName = key.toString();
+//
+//
+//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
+//        final Clause inColumn = QueryBuilder.eq("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED) );
+//
+//        final Statement statement = QueryBuilder.delete().from(TOKENS_TABLE)
+//            .where(inKey)
+//            .and(inColumn);
+//
+//        session.execute(statement);
+//
+//    }
+//
+//
+//    @Override
+//    public void invalidate(CacheScope scope) {
+//
+//        invalidateCQL(scope);
+//        logger.debug("Invalidated scope {}", scope.getApplication().getUuid());
+//
+//    }
+//
+//    private void invalidateCQL(CacheScope scope){
+//
+//        Preconditions.checkNotNull(scope, "scope is required");
+//
+//        // determine bucketed row-key based application UUID
+//        final String rowKeyString = scope.getApplication().getUuid().toString();
+//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
+//
+//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
+//
+//        final Statement statement = QueryBuilder.delete().from(TOKENS_TABLE)
+//            .where(inKey);
+//
+//        session.execute(statement);
+//
+//    }
+//
+    @Override
+    public Collection<MultiTenantColumnFamilyDefinition> getColumnFamilies() {
+
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Collection<TableDefinition> getTables() {
+
+        final TableDefinition tokens =
+            new TableDefinitionImpl(
+                cassandraConfig.getApplicationKeyspace(),
+                TOKENS_TABLE,
+                TOKENS_PARTITION_KEYS,
+                TOKENS_COLUMN_KEYS,
+                TOKENS_COLUMNS,
+                TableDefinitionImpl.CacheOption.KEYS,
+                TOKENS_CLUSTERING_ORDER);
+
+        final TableDefinition principalTokens =
+            new TableDefinitionImpl(
+                cassandraConfig.getApplicationKeyspace(),
+                PRINCIPAL_TOKENS_TABLE,
+                PRINCIPAL_TOKENS_PARTITION_KEYS,
+                PRINCIPAL_TOKENS_COLUMN_KEYS,
+                PRINCIPAL_TOKENS_COLUMNS,
+                TableDefinitionImpl.CacheOption.KEYS,
+                PRINCIPAL_TOKENS_CLUSTERING_ORDER);
+
+        return Arrays.asList(tokens, principalTokens);
+    }
+//
+//
+//
+//    private ByteBuffer getPartitionKey(CacheScope scope, String key, int bucketNumber){
+//
+//        return serializeKeys(scope.getApplication().getUuid(),
+//            scope.getApplication().getType(), bucketNumber, key);
+//
+//    }
+
+    private static ByteBuffer serializeTokenKey(UUID ownerUUID, String ownerType, int bucketNumber, String rowKeyString ){
+
+        List<Object> keys = new ArrayList<>(4);
+        keys.add(0, ownerUUID);
+        keys.add(1, ownerType);
+        keys.add(2, bucketNumber);
+        keys.add(3, rowKeyString);
+
+        // UUIDs are 16 bytes, allocate the buffer accordingly
+        int size = 16+ownerType.getBytes().length+rowKeyString.getBytes().length;
+
+        // ints are 4 bytes, add for the bucket
+        size += 4;
+
+
+        // we always need to add length for the 2 byte short and 1 byte equality
+        size += keys.size()*3;
+
+        ByteBuffer stuff = ByteBuffer.allocate(size);
+
+        for (Object key : keys) {
+
+            ByteBuffer kb = DataType.serializeValue(key, ProtocolVersion.NEWEST_SUPPORTED);
+            if (kb == null) {
+                kb = ByteBuffer.allocate(0);
+            }
+
+            stuff.putShort((short) kb.remaining());
+            stuff.put(kb.slice());
+            stuff.put((byte) 0);
+
+
+        }
+        stuff.flip();
+        return stuff;
+
+    }
+
+    private static ByteBuffer serializeKeys(UUID ownerUUID, String ownerType, int bucketNumber, String rowKeyString ){
+
+        List<Object> keys = new ArrayList<>(4);
+        keys.add(0, ownerUUID);
+        keys.add(1, ownerType);
+        keys.add(2, bucketNumber);
+        keys.add(3, rowKeyString);
+
+        // UUIDs are 16 bytes, allocate the buffer accordingly
+        int size = 16+ownerType.getBytes().length+rowKeyString.getBytes().length;
+
+        // ints are 4 bytes, add for the bucket
+        size += 4;
+
+
+        // we always need to add length for the 2 byte short and 1 byte equality
+        size += keys.size()*3;
+
+        ByteBuffer stuff = ByteBuffer.allocate(size);
+
+        for (Object key : keys) {
+
+            ByteBuffer kb = DataType.serializeValue(key, ProtocolVersion.NEWEST_SUPPORTED);
+            if (kb == null) {
+                kb = ByteBuffer.allocate(0);
+            }
+
+            stuff.putShort((short) kb.remaining());
+            stuff.put(kb.slice());
+            stuff.put((byte) 0);
+
+
+        }
+        stuff.flip();
+        return stuff;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
new file mode 100644
index 0000000..b454d73
--- /dev/null
+++ b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.usergrid.persistence.token;
+
+
+import org.apache.usergrid.persistence.token.guice.TokenModule;
+import org.apache.usergrid.persistence.token.impl.TokenSerialization;
+import org.apache.usergrid.persistence.token.impl.TokenSerializationImpl;
+import org.apache.usergrid.persistence.core.guice.CommonModule;
+
+
+
+public class TokenTestModule extends org.apache.usergrid.persistence.core.guice.TestModule {
+
+    @Override
+    protected void configure() {
+
+        install( new CommonModule() );
+        install( new TokenModule() );
+
+        bind(TokenSerialization.class).to(TokenSerializationImpl.class).asEagerSingleton();
+    }
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/179f12db/stack/corepersistence/token/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/test/resources/log4j.properties b/stack/corepersistence/token/src/test/resources/log4j.properties
new file mode 100644
index 0000000..d9f6b7f
--- /dev/null
+++ b/stack/corepersistence/token/src/test/resources/log4j.properties
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# suppress inspection "UnusedProperty" for whole file
+log4j.rootLogger=INFO,stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %c{3}.%M(%L)<%t>- %m%n
+
+#log4j.logger.com.datastax.driver.core=TRACE
+log4j.logger.org.safehaus.chop.plugin=DEBUG
+log4j.logger.org.safehaus.guicyfig=ERROR
+log4j.logger.org.safehaus.chop.api.store.amazon=DEBUG
+log4j.logger.org.apache.http=ERROR
+log4j.logger.com.amazonaws.request=ERROR
+log4j.logger.cassandra.db=ERROR
+
+#log4j.logger.org.apache.usergrid=DEBUG
+#log4j.logger.org.apache.usergrid.persistence.collection=TRACE
+log4j.logger.org.apache.usergrid.persistence.collection.mvcc.stage.delete.VersionCompact=TRACE
+


[6/7] usergrid git commit: Fix precondition checks and add another try/catch around the token workflow org id.

Posted by mr...@apache.org.
Fix precondition checks and add another try/catch around the token workflow org id.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/c0ba7103
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/c0ba7103
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/c0ba7103

Branch: refs/heads/master
Commit: c0ba7103949564dd9cebc3631fe8e5002a7e73d2
Parents: 9963449
Author: Michael Russo <ru...@google.com>
Authored: Mon Jun 19 08:49:57 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Mon Jun 19 08:49:57 2017 -0700

----------------------------------------------------------------------
 .../persistence/token/impl/TokenSerializationImpl.java       | 8 ++++----
 .../usergrid/security/tokens/impl/TokenServiceImpl.java      | 6 +++++-
 2 files changed, 9 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/c0ba7103/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
index 240da00..7825da0 100644
--- a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
@@ -192,9 +192,9 @@ public class TokenSerializationImpl implements TokenSerialization {
     public void updateTokenAccessTime(UUID tokenUUID, long accessedTime, long inactiveTime, int ttl ){
 
         Preconditions.checkNotNull(tokenUUID, "token UUID is required");
-        Preconditions.checkNotNull(accessedTime, "accessedTime is required");
-        Preconditions.checkNotNull(inactiveTime, "inactiveTime is required");
-        Preconditions.checkNotNull(ttl, "ttl is required");
+        Preconditions.checkArgument(accessedTime > -1 , "accessedTime is required to be positive");
+        Preconditions.checkArgument(inactiveTime > -1 , "inactiveTime is required to be positive");
+        Preconditions.checkArgument(ttl > -1 , "ttl is required to be positive");
 
         logger.trace("updateTokenAccessTime, token UUID: {}, accessedTime: {}, inactiveTime: {}, ttl: {}",
             tokenUUID, accessedTime, inactiveTime, ttl);
@@ -287,7 +287,7 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         Preconditions.checkNotNull(tokenUUID, "tokenUUID is required");
         Preconditions.checkNotNull(tokenUUID, "tokenInfo is required");
-        Preconditions.checkNotNull(ttl, "ttl is required");
+        Preconditions.checkArgument(ttl > -1 , "ttl is required to be positive");
 
         logger.trace("putTokenInfo, token UUID: {}, tokenInfo: {}, ttl: {}", tokenUUID, tokenInfo, ttl);
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c0ba7103/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
index f149a1f..05859ad 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
@@ -456,7 +456,11 @@ public class TokenServiceImpl implements TokenService {
 
         UUID workflowOrgId = null;
         if (tokenDetails.containsKey(TOKEN_WORKFLOW_ORG_ID)) {
-            workflowOrgId = (UUID) tokenDetails.get(TOKEN_WORKFLOW_ORG_ID);
+            try {
+                workflowOrgId = (UUID) tokenDetails.get(TOKEN_WORKFLOW_ORG_ID);
+            } catch (ClassCastException cce){
+                logger.error("Unable to cast {} to primitive UUID type", TOKEN_WORKFLOW_ORG_ID);
+            }
         }
 
         return new TokenInfo( uuid, type, created, accessed, inactive, duration, principal, state, workflowOrgId );


[5/7] usergrid git commit: Add try/catch around fetching and casting of token info from serialization map. Also, throw exceptions early.

Posted by mr...@apache.org.
Add try/catch around fetching and casting of token info from serialization map. Also, throw exceptions early.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/99634490
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/99634490
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/99634490

Branch: refs/heads/master
Commit: 9963449003b1559277780ab193fb529ddfdf3b4b
Parents: bea9a41
Author: Michael Russo <ru...@google.com>
Authored: Mon Jun 19 08:31:31 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Mon Jun 19 08:31:31 2017 -0700

----------------------------------------------------------------------
 .../security/tokens/impl/TokenServiceImpl.java  | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/99634490/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
index 21bd0db..f149a1f 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
@@ -417,11 +417,21 @@ public class TokenServiceImpl implements TokenService {
             throw new InvalidTokenException( "Token not found in database" );
         }
 
-        String type = (String) tokenDetails.get(TOKEN_TYPE);
-        long created = (long) tokenDetails.get(TOKEN_CREATED);
-        long accessed = (long) tokenDetails.get(TOKEN_ACCESSED);
-        long inactive = (long) tokenDetails.get(TOKEN_INACTIVE);
-        long duration = (long) tokenDetails.get(TOKEN_DURATION);
+        String type;
+        long created, accessed, inactive, duration;
+        try {
+            type = (String) tokenDetails.get(TOKEN_TYPE);
+            created = (long) tokenDetails.get(TOKEN_CREATED);
+            accessed = (long) tokenDetails.get(TOKEN_ACCESSED);
+            inactive = (long) tokenDetails.get(TOKEN_INACTIVE);
+            duration = (long) tokenDetails.get(TOKEN_DURATION);
+        } catch (ClassCastException cce){
+            logger.error("Unable to cast token info to primitive type: {}", cce);
+            throw new RuntimeException("Unable to cast token info to primitive type");
+        } catch (NullPointerException npe){
+            logger.error("Unable to obtain token info from serialization layer, on or more missing properties: {}", npe);
+            throw new RuntimeException("Unable to obtain token info from serialization layer, on or more missing properties");
+        }
 
         String principalTypeStr = (String) tokenDetails.get(TOKEN_PRINCIPAL_TYPE);
 


[4/7] usergrid git commit: Fix issue where tokenInfo was not being updated with latest inactive value. Add trace logging to TokenSerializationImpl. Fix issue with push notifications where the InactiveDeviceManager was making a duplicate (yet incorrect) q

Posted by mr...@apache.org.
Fix issue where tokenInfo was not being updated with latest inactive value. Add trace logging to TokenSerializationImpl. Fix issue with push notifications where the InactiveDeviceManager was making a duplicate (yet incorrect) query for devices.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/bea9a418
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/bea9a418
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/bea9a418

Branch: refs/heads/master
Commit: bea9a4180ebadb79e7f101cfc6d0d06efc39b359
Parents: 146e47d
Author: Michael Russo <ru...@google.com>
Authored: Sun Jun 18 12:36:56 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Sun Jun 18 12:36:56 2017 -0700

----------------------------------------------------------------------
 .../token/impl/TokenSerializationImpl.java      | 35 ++++++++++++++------
 .../security/tokens/impl/TokenServiceImpl.java  |  9 +++--
 .../notifications/InactiveDeviceManager.java    |  6 ----
 3 files changed, 31 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/bea9a418/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
index 2207b99..240da00 100644
--- a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
@@ -130,22 +130,27 @@ public class TokenSerializationImpl implements TokenSerialization {
     public void deleteTokens(final List<UUID> tokenUUIDs, final ByteBuffer principalKeyBuffer){
 
         Preconditions.checkNotNull(tokenUUIDs, "token UUID list is required");
+        Preconditions.checkNotNull(tokenUUIDs, "principalKeyBuffer is required");
 
-        final BatchStatement batchStatement = new BatchStatement();
+        logger.trace("deleteTokens, token UUIDs: {}", tokenUUIDs);
 
-        tokenUUIDs.forEach( tokenUUID -> batchStatement.add(
-        QueryBuilder.delete()
-            .from(TOKENS_TABLE)
-            .where(QueryBuilder
-                .eq("key", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED)))));
+        final BatchStatement batchStatement = new BatchStatement();
 
-        if(principalKeyBuffer != null){
+        tokenUUIDs.forEach( tokenUUID ->
             batchStatement.add(
                 QueryBuilder.delete()
-                    .from(PRINCIPAL_TOKENS_TABLE)
+                    .from(TOKENS_TABLE)
                     .where(QueryBuilder
-                        .eq("key", principalKeyBuffer)));
-        }
+                        .eq("key", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED)))
+            )
+        );
+
+        batchStatement.add(
+            QueryBuilder.delete()
+                .from(PRINCIPAL_TOKENS_TABLE)
+                .where(QueryBuilder
+                    .eq("key", principalKeyBuffer)));
+
 
         session.execute(batchStatement);
 
@@ -157,6 +162,9 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         Preconditions.checkNotNull(tokenUUID, "token UUID is required");
 
+        logger.trace("revokeToken, token UUID: {}", tokenUUID);
+
+
         final BatchStatement batchStatement = new BatchStatement();
 
         batchStatement.add(
@@ -188,6 +196,8 @@ public class TokenSerializationImpl implements TokenSerialization {
         Preconditions.checkNotNull(inactiveTime, "inactiveTime is required");
         Preconditions.checkNotNull(ttl, "ttl is required");
 
+        logger.trace("updateTokenAccessTime, token UUID: {}, accessedTime: {}, inactiveTime: {}, ttl: {}",
+            tokenUUID, accessedTime, inactiveTime, ttl);
 
         final BatchStatement batchStatement = new BatchStatement();
         final Clause inKey =
@@ -265,6 +275,8 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         });
 
+        logger.trace("getTokenInfo, info: {}", tokenInfo);
+
         return tokenInfo;
     }
 
@@ -277,6 +289,7 @@ public class TokenSerializationImpl implements TokenSerialization {
         Preconditions.checkNotNull(tokenUUID, "tokenInfo is required");
         Preconditions.checkNotNull(ttl, "ttl is required");
 
+        logger.trace("putTokenInfo, token UUID: {}, tokenInfo: {}, ttl: {}", tokenUUID, tokenInfo, ttl);
 
         final BatchStatement batchStatement = new BatchStatement();
         final Using usingTTL = QueryBuilder.ttl(ttl);
@@ -332,6 +345,8 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         rows.forEach(row -> tokenUUIDs.add(row.getUUID("column1")));
 
+        logger.trace("getTokensForPrincipal, token UUIDs: {}", tokenUUIDs);
+
         return tokenUUIDs;
     }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/bea9a418/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
index d93ecc0..21bd0db 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
@@ -310,9 +310,12 @@ public class TokenServiceImpl implements TokenService {
             long maxTokenTtl = getMaxTtl(TokenCategory.getFromBase64String(token), tokenInfo.getPrincipal());
 
             long inactive = now - tokenInfo.getAccessed();
-            // Long.MIN_VALUE indicates that nothing needs to be updated for token inactive property
-            if (inactive < tokenInfo.getInactive()) {
-               inactive = Long.MIN_VALUE;
+            if (inactive > tokenInfo.getInactive()) {
+                tokenInfo.setInactive(inactive);
+            }else{
+                // Long.MIN_VALUE indicates that nothing needs to be updated for token inactive property in
+                // tokenSerialization.updateTokenAccessTime()
+                inactive = Long.MIN_VALUE;
             }
 
             tokenSerialization.updateTokenAccessTime(uuid, now, inactive, calcTokenTime(tokenInfo.getExpiration(maxTokenTtl)));

http://git-wip-us.apache.org/repos/asf/usergrid/blob/bea9a418/stack/services/src/main/java/org/apache/usergrid/services/notifications/InactiveDeviceManager.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/notifications/InactiveDeviceManager.java b/stack/services/src/main/java/org/apache/usergrid/services/notifications/InactiveDeviceManager.java
index 37650c5..6693939 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/notifications/InactiveDeviceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/notifications/InactiveDeviceManager.java
@@ -64,12 +64,6 @@ public class InactiveDeviceManager {
                     for (Entity e : results.getEntities()) {
                         entityManager.updateProperties(e, clearPushtokenMap);
                     }
-                    // uuid
-                    query = Query.fromQL( notifier.getName() + notfierPostFix  + " = " + entry.getKey() + "");
-                    results = entityManager.searchCollection(entityManager.getApplication(),  "devices", query);
-                    for (Entity e : results.getEntities()) {
-                        entityManager.updateProperties(e, clearPushtokenMap);
-                    }
                 }catch (Exception e){
                     logger.error("failed to remove token",e);
                 }


[7/7] usergrid git commit: Merge commit 'refs/pull/573/head' of github.com:apache/usergrid

Posted by mr...@apache.org.
Merge commit 'refs/pull/573/head' of github.com:apache/usergrid


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/375814e0
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/375814e0
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/375814e0

Branch: refs/heads/master
Commit: 375814e00330f28b4209c7595ed591187abbb245
Parents: d8a7e10 c0ba710
Author: Michael Russo <ru...@google.com>
Authored: Mon Jun 19 12:58:30 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Mon Jun 19 12:58:30 2017 -0700

----------------------------------------------------------------------
 .../src/test/resources/usergrid-test.properties |   2 -
 stack/core/pom.xml                              |   6 +
 .../usergrid/corepersistence/CoreModule.java    |   3 +-
 .../usergrid/corepersistence/CpSetup.java       |  11 -
 .../persistence/cassandra/CassandraService.java |   3 -
 .../map/impl/MapSerializationImpl.java          |  35 +-
 stack/corepersistence/pom.xml                   |   1 +
 stack/corepersistence/token/pom.xml             |  70 ++
 .../persistence/token/TokenSerialization.java   |  50 ++
 .../persistence/token/guice/TokenModule.java    |  44 +
 .../token/impl/TokenSerializationImpl.java      | 451 ++++++++++
 .../persistence/token/TestTokenModule.java      |  38 +
 .../token/TokenSerializationTest.java           | 202 +++++
 .../token/src/test/resources/log4j.properties   |  38 +
 .../resources/usergrid-standalone.properties    |   2 -
 .../rest/management/ManagementResource.java     |   4 +-
 .../rest/management/users/UserResource.java     |   2 +-
 .../rest/management/users/UsersResource.java    |   3 +-
 .../rest/management/ManagementResourceIT.java   |   8 +-
 .../security/sso/SSOProviderFactory.java        |   2 +-
 .../tokens/cassandra/TokenServiceImpl.java      | 848 -------------------
 .../security/tokens/impl/TokenServiceImpl.java  | 748 ++++++++++++++++
 .../notifications/InactiveDeviceManager.java    |   6 -
 .../resources/usergrid-services-context.xml     |   3 +-
 .../security/tokens/TokenServiceIT.java         |   2 +-
 .../test/resources/testApplicationContext.xml   |   2 +-
 26 files changed, 1680 insertions(+), 904 deletions(-)
----------------------------------------------------------------------



[3/7] usergrid git commit: Finish convert token service persistence to Datastax. Add tests, and rename the package for TokenServiceImpl to impl from cassandra.

Posted by mr...@apache.org.
Finish convert token service persistence to Datastax. Add tests, and rename the package for TokenServiceImpl to impl from cassandra.


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/146e47d6
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/146e47d6
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/146e47d6

Branch: refs/heads/master
Commit: 146e47d668788d72c4fc54a61b7155eeeef508b6
Parents: 179f12d
Author: Michael Russo <ru...@google.com>
Authored: Sat Jun 17 23:47:47 2017 -0700
Committer: Michael Russo <ru...@google.com>
Committed: Sat Jun 17 23:47:47 2017 -0700

----------------------------------------------------------------------
 .../src/test/resources/usergrid-test.properties |   2 -
 stack/core/pom.xml                              |   6 +
 .../usergrid/corepersistence/CoreModule.java    |   2 +
 .../usergrid/corepersistence/CpSetup.java       |  11 -
 .../persistence/cassandra/CassandraService.java |   3 -
 .../map/impl/MapSerializationImpl.java          |  35 +-
 .../persistence/token/TokenSerialization.java   |  50 ++
 .../persistence/token/guice/TokenModule.java    |  10 +-
 .../token/impl/TokenSerialization.java          |  50 --
 .../token/impl/TokenSerializationImpl.java      | 482 +++++------
 .../persistence/token/TestTokenModule.java      |  38 +
 .../token/TokenSerializationTest.java           | 202 +++++
 .../persistence/token/TokenTestModule.java      |  40 -
 .../resources/usergrid-standalone.properties    |   2 -
 .../rest/management/ManagementResource.java     |   4 +-
 .../rest/management/users/UserResource.java     |   2 +-
 .../rest/management/users/UsersResource.java    |   3 +-
 .../rest/management/ManagementResourceIT.java   |   8 +-
 .../security/sso/SSOProviderFactory.java        |   2 +-
 .../tokens/cassandra/TokenServiceImpl.java      | 848 -------------------
 .../security/tokens/impl/TokenServiceImpl.java  | 731 ++++++++++++++++
 .../resources/usergrid-services-context.xml     |   3 +-
 .../security/tokens/TokenServiceIT.java         |   2 +-
 .../test/resources/testApplicationContext.xml   |   2 +-
 24 files changed, 1253 insertions(+), 1285 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/config/src/test/resources/usergrid-test.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/test/resources/usergrid-test.properties b/stack/config/src/test/resources/usergrid-test.properties
index 143d60a..5def24e 100644
--- a/stack/config/src/test/resources/usergrid-test.properties
+++ b/stack/config/src/test/resources/usergrid-test.properties
@@ -104,8 +104,6 @@ collection.uniquevalues.authoritative.region=us-east
 
 usergrid.counter.batch.interval=10
 #usergrid.auth.token_secret_salt=super secret token value
-#usergrid.auth.token_expires_from_last_use=false
-#usergrid.auth.token_refresh_reuses_id=false
 
 # max time to persist tokens for (milliseconds)
 #usergrid.auth.token.persist.expires=0

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/core/pom.xml
----------------------------------------------------------------------
diff --git a/stack/core/pom.xml b/stack/core/pom.xml
index 09047bb..658320e 100644
--- a/stack/core/pom.xml
+++ b/stack/core/pom.xml
@@ -428,6 +428,12 @@
 
         <dependency>
             <groupId>org.apache.usergrid</groupId>
+            <artifactId>token</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.usergrid</groupId>
             <artifactId>actorsystem</artifactId>
             <version>${project.version}</version>
         </dependency>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/core/src/main/java/org/apache/usergrid/corepersistence/CoreModule.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CoreModule.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CoreModule.java
index af297f2..ec6b775 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CoreModule.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CoreModule.java
@@ -44,6 +44,7 @@ import org.apache.usergrid.persistence.core.scope.ApplicationScope;
 import org.apache.usergrid.persistence.graph.guice.GraphModule;
 import org.apache.usergrid.persistence.graph.serialization.impl.migration.GraphNode;
 import org.apache.usergrid.persistence.index.guice.IndexModule;
+import org.apache.usergrid.persistence.token.guice.TokenModule;
 import org.safehaus.guicyfig.GuicyFigModule;
 
 import java.util.Properties;
@@ -67,6 +68,7 @@ public class CoreModule extends AbstractModule {
         install( new CommonModule());
         install( new LockModule());
         install( new CacheModule());
+        install( new TokenModule());
         install( new CollectionModule() {
             /**
              * configure our migration data provider for all entities in the system

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpSetup.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpSetup.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpSetup.java
index 5d50ef8..5aa556a 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpSetup.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpSetup.java
@@ -33,14 +33,9 @@ import org.apache.usergrid.persistence.exceptions.OrganizationAlreadyExistsExcep
 
 import com.google.inject.Injector;
 
-import me.prettyprint.hector.api.ddl.ComparatorType;
-
-import static me.prettyprint.hector.api.factory.HFactory.createColumnFamilyDefinition;
 import static org.apache.usergrid.persistence.cassandra.CassandraPersistenceUtils.getCfDefs;
 import static org.apache.usergrid.persistence.cassandra.CassandraService.DEFAULT_ORGANIZATION;
 import static org.apache.usergrid.persistence.cassandra.CassandraService.MANAGEMENT_APPLICATION;
-import static org.apache.usergrid.persistence.cassandra.CassandraService.PRINCIPAL_TOKEN_CF;
-import static org.apache.usergrid.persistence.cassandra.CassandraService.TOKENS_CF;
 import static org.apache.usergrid.persistence.cassandra.CassandraService.getApplicationKeyspace;
 
 
@@ -116,12 +111,6 @@ public class CpSetup implements Setup {
 
         logger.info( "Initialize keyspace and legacy column families" );
 
-        cass.createColumnFamily( getApplicationKeyspace(),
-            createColumnFamilyDefinition( getApplicationKeyspace(), TOKENS_CF, ComparatorType.BYTESTYPE ) );
-
-        cass.createColumnFamily( getApplicationKeyspace(),
-            createColumnFamilyDefinition( getApplicationKeyspace(), PRINCIPAL_TOKEN_CF, ComparatorType.UUIDTYPE ) );
-
         cass.createColumnFamilies( getApplicationKeyspace(),
             getCfDefs( ApplicationCF.class, getApplicationKeyspace() ) );
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
index f8b1f6c..3e08cf7 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
@@ -64,9 +64,6 @@ public class CassandraService {
 
     public static final boolean USE_VIRTUAL_KEYSPACES = true;
 
-    public static final String TOKENS_CF = "Tokens";
-    public static final String PRINCIPAL_TOKEN_CF = "PrincipalTokens";
-
     public static final int DEFAULT_COUNT = 1000;
     public static final int ALL_COUNT = 100000;
     public static final int INDEX_ENTRY_LIST_COUNT = 1000;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/map/src/main/java/org/apache/usergrid/persistence/map/impl/MapSerializationImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/map/src/main/java/org/apache/usergrid/persistence/map/impl/MapSerializationImpl.java b/stack/corepersistence/map/src/main/java/org/apache/usergrid/persistence/map/impl/MapSerializationImpl.java
index 26a1890..dda50c6 100644
--- a/stack/corepersistence/map/src/main/java/org/apache/usergrid/persistence/map/impl/MapSerializationImpl.java
+++ b/stack/corepersistence/map/src/main/java/org/apache/usergrid/persistence/map/impl/MapSerializationImpl.java
@@ -154,43 +154,44 @@ public class MapSerializationImpl implements MapSerialization {
         Preconditions.checkNotNull( key, "key is required" );
         Preconditions.checkNotNull( value, "value is required" );
 
+        final BatchStatement batchStatement = new BatchStatement();
+
         Statement mapEntry;
         Statement mapKey;
         if (ttl > 0){
             Using timeToLive = QueryBuilder.ttl(ttl);
 
-            mapEntry = QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
+             batchStatement.add(QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
                 .using(timeToLive)
                 .value("key", getMapEntryPartitionKey(scope, key))
                 .value("column1", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED))
-                .value("value", DataType.text().serialize(value, ProtocolVersion.NEWEST_SUPPORTED));
+                .value("value", DataType.text().serialize(value, ProtocolVersion.NEWEST_SUPPORTED)));
 
 
             final int bucket = BUCKET_LOCATOR.getCurrentBucket( scope.getName() );
-            mapKey = QueryBuilder.insertInto(MAP_KEYS_TABLE)
+            batchStatement.add(QueryBuilder.insertInto(MAP_KEYS_TABLE)
                 .using(timeToLive)
                 .value("key", getMapKeyPartitionKey(scope, bucket))
                 .value("column1", DataType.text().serialize(key, ProtocolVersion.NEWEST_SUPPORTED))
-                .value("value", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED));
+                .value("value", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED)));
         }else{
 
-            mapEntry = QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
+            batchStatement.add(QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
                 .value("key", getMapEntryPartitionKey(scope, key))
                 .value("column1", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED))
-                .value("value", DataType.text().serialize(value, ProtocolVersion.NEWEST_SUPPORTED));
+                .value("value", DataType.text().serialize(value, ProtocolVersion.NEWEST_SUPPORTED)));
 
             // get a bucket number for the map keys table
             final int bucket = BUCKET_LOCATOR.getCurrentBucket( scope.getName() );
 
-            mapKey = QueryBuilder.insertInto(MAP_KEYS_TABLE)
+            batchStatement.add(QueryBuilder.insertInto(MAP_KEYS_TABLE)
                 .value("key", getMapKeyPartitionKey(scope, bucket))
                 .value("column1", DataType.text().serialize(key, ProtocolVersion.NEWEST_SUPPORTED))
-                .value("value", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED));
+                .value("value", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED)));
 
         }
 
-        session.execute(mapEntry);
-        session.execute(mapKey);
+        session.execute(batchStatement);
 
     }
 
@@ -211,23 +212,23 @@ public class MapSerializationImpl implements MapSerialization {
         Preconditions.checkNotNull( key, "key is required" );
         Preconditions.checkNotNull( putUuid, "value is required" );
 
+        final BatchStatement batchStatement = new BatchStatement();
 
-        Statement mapEntry = QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
+        batchStatement.add(QueryBuilder.insertInto(MAP_ENTRIES_TABLE)
             .value("key", getMapEntryPartitionKey(scope, key))
             .value("column1", DataType.cboolean().serialize(true, ProtocolVersion.NEWEST_SUPPORTED))
-            .value("value", DataType.uuid().serialize(putUuid, ProtocolVersion.NEWEST_SUPPORTED));
+            .value("value", DataType.uuid().serialize(putUuid, ProtocolVersion.NEWEST_SUPPORTED)));
 
-        session.execute(mapEntry);
 
 
         final int bucket = BUCKET_LOCATOR.getCurrentBucket( scope.getName() );
-        Statement mapKey;
-        mapKey = QueryBuilder.insertInto(MAP_KEYS_TABLE)
+        batchStatement.add(QueryBuilder.insertInto(MAP_KEYS_TABLE)
             .value("key", getMapKeyPartitionKey(scope, bucket))
             .value("column1", DataType.text().serialize(key, ProtocolVersion.NEWEST_SUPPORTED))
-            .value("value", DataType.serializeValue(null, ProtocolVersion.NEWEST_SUPPORTED));
+            .value("value", DataType.serializeValue(null, ProtocolVersion.NEWEST_SUPPORTED)));
+
+        session.execute(batchStatement);
 
-        session.execute(mapKey);
     }
 
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/TokenSerialization.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/TokenSerialization.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/TokenSerialization.java
new file mode 100644
index 0000000..22a93f0
--- /dev/null
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/TokenSerialization.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.persistence.token;
+
+
+import org.apache.usergrid.persistence.core.migration.schema.Migration;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+
+/**
+ * Serialize token information to/from Cassandra. This was ported over to use a newer cassandra client from the old
+ * persistence code @
+ *
+ *     https://github.com/apache/usergrid/tree/3f819dc0679f84edb57c52e69b58622417cfd59f
+ *     org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl
+ *
+ */
+public interface TokenSerialization extends Migration {
+
+    void deleteTokens(List<UUID> tokenUUIDs, ByteBuffer principalKeyBuffer);
+
+    void revokeToken(UUID tokenUUID, ByteBuffer principalKeyBuffer);
+
+    void updateTokenAccessTime(UUID tokenUUID, long accessedTime, long inactiveTime, int ttl );
+
+    Map<String, Object> getTokenInfo(UUID tokenUUID);
+
+    void putTokenInfo(UUID tokenUUID, Map<String, Object> tokenInfo, ByteBuffer principalKeyBuffer, int ttl);
+
+    List<UUID> getTokensForPrincipal(ByteBuffer principalKeyBuffer);
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
index 13d6b43..a8fdd4c 100644
--- a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/guice/TokenModule.java
@@ -20,11 +20,9 @@ package org.apache.usergrid.persistence.token.guice;
 import com.google.inject.AbstractModule;
 import com.google.inject.Key;
 import com.google.inject.multibindings.Multibinder;
-import org.apache.usergrid.persistence.cache.CacheFactory;
-import org.apache.usergrid.persistence.cache.impl.CacheFactoryImpl;
-import org.apache.usergrid.persistence.cache.impl.TokenSerialization;
-import org.apache.usergrid.persistence.cache.impl.TokenSerializationImpl;
 import org.apache.usergrid.persistence.core.migration.schema.Migration;
+import org.apache.usergrid.persistence.token.TokenSerialization;
+import org.apache.usergrid.persistence.token.impl.TokenSerializationImpl;
 
 
 /**
@@ -35,12 +33,10 @@ public class TokenModule extends AbstractModule {
     @Override
     protected void configure() {
 
-        bind( CacheFactory.class ).to( CacheFactoryImpl.class );
-
         bind( TokenSerialization.class ).to( TokenSerializationImpl.class );
 
         Multibinder<Migration> migrationBinding = Multibinder.newSetBinder( binder(), Migration.class );
-        migrationBinding.addBinding().to(Key.get(TokenSerialization.class));
+        migrationBinding.addBinding().to(  Key.get( TokenSerialization.class ) );
 
     }
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
deleted file mode 100644
index bf9337f..0000000
--- a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerialization.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.usergrid.persistence.token.impl;
-
-
-import org.apache.usergrid.persistence.core.migration.schema.Migration;
-
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-
-/**
- * Serialize token information to/from Cassandra. This was ported over to use a newer cassandra client from the old
- * persistence code @
- *
- *     https://github.com/apache/usergrid/tree/3f819dc0679f84edb57c52e69b58622417cfd59f
- *     org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl
- *
- */
-public interface TokenSerialization extends Migration {
-
-    void deleteToken(UUID tokenUUID);
-
-    void revokeToken(UUID tokenUUID, ByteBuffer principalKeyBuffer);
-
-    void updateTokenAccessTime(UUID tokenUUID, int accessdTime, int inactiveTime );
-
-    Map<String, Object> getTokenInfo(UUID tokenUUID);
-
-    void putTokenInfo(UUID tokenUUID, Map<String, Object> tokenInfo);
-
-    List<UUID> getTokensForPrincipal(ByteBuffer principalKeyBuffer);
-
-}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
index b07472d..2207b99 100644
--- a/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
+++ b/stack/corepersistence/token/src/main/java/org/apache/usergrid/persistence/token/impl/TokenSerializationImpl.java
@@ -17,22 +17,18 @@
 package org.apache.usergrid.persistence.token.impl;
 
 import com.datastax.driver.core.*;
-import com.datastax.driver.core.querybuilder.Clause;
-import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.datastax.driver.core.querybuilder.*;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.smile.SmileFactory;
 import com.google.common.base.Preconditions;
-import com.google.common.hash.Funnel;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import org.apache.usergrid.persistence.core.CassandraConfig;
 import org.apache.usergrid.persistence.core.astyanax.*;
 import org.apache.usergrid.persistence.core.datastax.CQLUtils;
 import org.apache.usergrid.persistence.core.datastax.TableDefinition;
 import org.apache.usergrid.persistence.core.datastax.impl.TableDefinitionImpl;
-import org.apache.usergrid.persistence.core.shard.ExpandingShardLocator;
-import org.apache.usergrid.persistence.core.shard.StringHashUtils;
+import org.apache.usergrid.persistence.token.TokenSerialization;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,8 +37,9 @@ import java.util.*;
 
 
 /**
- * Serialize cache to Cassandra.
+ * Serialize tokens and their details to Cassandra.
  */
+@Singleton
 public class TokenSerializationImpl implements TokenSerialization {
 
     public static final Logger logger = LoggerFactory.getLogger(TokenSerializationImpl.class);
@@ -51,17 +48,18 @@ public class TokenSerializationImpl implements TokenSerialization {
 
     private ObjectMapper smileMapper = new ObjectMapper( smile );
 
-    private static final String TOKEN_UUID = "uuid";
-    private static final String TOKEN_TYPE = "type";
-    private static final String TOKEN_CREATED = "created";
-    private static final String TOKEN_ACCESSED = "accessed";
-    private static final String TOKEN_INACTIVE = "inactive";
-    private static final String TOKEN_DURATION = "duration";
-    private static final String TOKEN_PRINCIPAL_TYPE = "principal";
-    private static final String TOKEN_ENTITY = "entity";
-    private static final String TOKEN_APPLICATION = "application";
-    private static final String TOKEN_STATE = "state";
-    private static final String TOKEN_WORKFLOW_ORG_ID = "workflowOrgId";
+    public static final String TOKEN_UUID = "uuid";
+    public static final String TOKEN_TYPE = "type";
+    public static final String TOKEN_CREATED = "created";
+    public static final String TOKEN_ACCESSED = "accessed";
+    public static final String TOKEN_INACTIVE = "inactive";
+    public static final String TOKEN_DURATION = "duration";
+    public static final String TOKEN_PRINCIPAL_TYPE = "principal";
+    public static final String TOKEN_ENTITY = "entity";
+    public static final String TOKEN_APPLICATION = "application";
+    public static final String TOKEN_STATE = "state";
+    public static final String TOKEN_WORKFLOW_ORG_ID = "workflowOrgId";
+    public static final String TOKEN_TYPE_ACCESS = "access";
 
     private static final Set<String> TOKEN_PROPERTIES;
 
@@ -81,8 +79,7 @@ public class TokenSerializationImpl implements TokenSerialization {
         TOKEN_PROPERTIES = Collections.unmodifiableSet(set);
     }
 
-    private static final HashSet<String> REQUIRED_TOKEN_PROPERTIES = new HashSet<String>();
-
+    public static final HashSet<String> REQUIRED_TOKEN_PROPERTIES = new HashSet<String>();
 
     static {
         REQUIRED_TOKEN_PROPERTIES.add( TOKEN_UUID );
@@ -93,8 +90,6 @@ public class TokenSerializationImpl implements TokenSerialization {
         REQUIRED_TOKEN_PROPERTIES.add( TOKEN_DURATION );
     }
 
-
-
     private static final String TOKENS_TABLE = CQLUtils.quote("Tokens");
     private static final Collection<String> TOKENS_PARTITION_KEYS = Collections.singletonList("key");
     private static final Collection<String> TOKENS_COLUMN_KEYS = Collections.singletonList("column1");
@@ -118,14 +113,10 @@ public class TokenSerializationImpl implements TokenSerialization {
         new HashMap<String, String>(){{ put( "column1", "ASC" ); }};
 
 
-
-
     private final Session session;
     private final CassandraConfig cassandraConfig;
 
 
-
-
     @Inject
     public TokenSerializationImpl(final Session session,
                                   final CassandraConfig cassandraConfig ) {
@@ -136,20 +127,106 @@ public class TokenSerializationImpl implements TokenSerialization {
 
 
     @Override
-    public void deleteToken(UUID tokenUUID){
+    public void deleteTokens(final List<UUID> tokenUUIDs, final ByteBuffer principalKeyBuffer){
+
+        Preconditions.checkNotNull(tokenUUIDs, "token UUID list is required");
+
+        final BatchStatement batchStatement = new BatchStatement();
+
+        tokenUUIDs.forEach( tokenUUID -> batchStatement.add(
+        QueryBuilder.delete()
+            .from(TOKENS_TABLE)
+            .where(QueryBuilder
+                .eq("key", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED)))));
+
+        if(principalKeyBuffer != null){
+            batchStatement.add(
+                QueryBuilder.delete()
+                    .from(PRINCIPAL_TOKENS_TABLE)
+                    .where(QueryBuilder
+                        .eq("key", principalKeyBuffer)));
+        }
+
+        session.execute(batchStatement);
 
     }
 
+
     @Override
-    public void revokeToken(UUID tokenUUID, ByteBuffer principalKeyBuffer){
+    public void revokeToken(final UUID tokenUUID, final ByteBuffer principalKeyBuffer){
+
+        Preconditions.checkNotNull(tokenUUID, "token UUID is required");
+
+        final BatchStatement batchStatement = new BatchStatement();
+
+        batchStatement.add(
+            QueryBuilder.delete()
+                .from(TOKENS_TABLE)
+                .where(QueryBuilder
+                    .eq("key", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED))));
+
+        if(principalKeyBuffer != null){
+            batchStatement.add(
+                QueryBuilder.delete()
+                    .from(PRINCIPAL_TOKENS_TABLE)
+                    .where(QueryBuilder
+                        .eq("key", principalKeyBuffer))
+                    .and(QueryBuilder
+                        .eq("column1", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED))));
+        }
+
+        session.execute(batchStatement);
 
     }
 
+
     @Override
-    public void updateTokenAccessTime(UUID tokenUUID, int accessdTime, int inactiveTime ){
+    public void updateTokenAccessTime(UUID tokenUUID, long accessedTime, long inactiveTime, int ttl ){
+
+        Preconditions.checkNotNull(tokenUUID, "token UUID is required");
+        Preconditions.checkNotNull(accessedTime, "accessedTime is required");
+        Preconditions.checkNotNull(inactiveTime, "inactiveTime is required");
+        Preconditions.checkNotNull(ttl, "ttl is required");
+
+
+        final BatchStatement batchStatement = new BatchStatement();
+        final Clause inKey =
+            QueryBuilder.eq("key", DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED));
+        final Clause whereTokenAccessed =
+            QueryBuilder.eq("column1", DataType.serializeValue(TOKEN_ACCESSED, ProtocolVersion.NEWEST_SUPPORTED));
+        final Clause whereTokenInactive =
+            QueryBuilder.eq("column1", DataType.serializeValue(TOKEN_INACTIVE, ProtocolVersion.NEWEST_SUPPORTED));
+
+        final Assignment setAccessedTime =
+            QueryBuilder.set("value", DataType.serializeValue(accessedTime, ProtocolVersion.NEWEST_SUPPORTED));
+        final Assignment setInactiveTime =
+            QueryBuilder.set("value", DataType.serializeValue(inactiveTime, ProtocolVersion.NEWEST_SUPPORTED));
+
+        final Using usingTTL = QueryBuilder.ttl(ttl);
+
+        if( inactiveTime != Long.MIN_VALUE){
+            batchStatement.add(
+                QueryBuilder
+                    .update(TOKENS_TABLE)
+                    .with(setInactiveTime)
+                    .where(inKey).and(whereTokenInactive)
+                    .using(usingTTL)
+            );
+        }
+
+        batchStatement.add(
+            QueryBuilder
+            .update(TOKENS_TABLE)
+            .with(setAccessedTime)
+            .where(inKey).and(whereTokenAccessed)
+            .using(usingTTL)
+        );
+
+        session.execute(batchStatement);
 
     }
 
+
     @Override
     public Map<String, Object> getTokenInfo(UUID tokenUUID){
 
@@ -159,7 +236,7 @@ public class TokenSerializationImpl implements TokenSerialization {
         TOKEN_PROPERTIES.forEach( prop ->
             tokenProperties.add(DataType.serializeValue(prop, ProtocolVersion.NEWEST_SUPPORTED)));
 
-        final ByteBuffer key = DataType.text().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED);
+        final ByteBuffer key = DataType.uuid().serialize(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED);
 
         final Clause inKey = QueryBuilder.eq("key", key);
         final Clause inColumn = QueryBuilder.in("column1", tokenProperties );
@@ -176,7 +253,8 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         rows.forEach( row -> {
 
-            final String name = row.getString("column1");
+            final String name = (String)DataType.text()
+                .deserialize(row.getBytes("column1"), ProtocolVersion.NEWEST_SUPPORTED);
             final Object value = deserializeColumnValue(name, row.getBytes("value"));
 
             if (value == null){
@@ -190,14 +268,71 @@ public class TokenSerializationImpl implements TokenSerialization {
         return tokenInfo;
     }
 
+
     @Override
-    public void putTokenInfo(UUID tokenUUID, Map<String, Object> tokenInfo){
+    public void putTokenInfo(final UUID tokenUUID, final Map<String, Object> tokenInfo,
+                             final ByteBuffer principalKeyBuffer, final int ttl){
+
+        Preconditions.checkNotNull(tokenUUID, "tokenUUID is required");
+        Preconditions.checkNotNull(tokenUUID, "tokenInfo is required");
+        Preconditions.checkNotNull(ttl, "ttl is required");
+
+
+        final BatchStatement batchStatement = new BatchStatement();
+        final Using usingTTL = QueryBuilder.ttl(ttl);
+
+        tokenInfo.forEach((key, value) -> {
+
+            ByteBuffer valueBuffer;
+            if(key.equalsIgnoreCase(TOKEN_STATE)){
+                valueBuffer = toByteBuffer(value);
+            }else{
+                valueBuffer = DataType.serializeValue(value, ProtocolVersion.NEWEST_SUPPORTED);
+            }
+
+            batchStatement.add(
+                QueryBuilder.insertInto(TOKENS_TABLE)
+                    .value("key", DataType.serializeValue(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED))
+                    .value("column1", DataType.serializeValue(key, ProtocolVersion.NEWEST_SUPPORTED))
+                    .value("value", valueBuffer)
+                    .using(usingTTL));
+
+        });
+
+        if(principalKeyBuffer != null){
+
+            batchStatement.add(
+                QueryBuilder.insertInto(PRINCIPAL_TOKENS_TABLE)
+                    .value("key", principalKeyBuffer)
+                    .value("column1", DataType.serializeValue(tokenUUID, ProtocolVersion.NEWEST_SUPPORTED))
+                    .value("value", ByteBuffer.wrap( new byte[] { 0 } ))
+                    .using(usingTTL));
+
+        }
+
+        session.execute(batchStatement);
 
     }
 
+
     @Override
     public List<UUID> getTokensForPrincipal(ByteBuffer principalKeyBuffer){
-        return new ArrayList<>();
+
+        Preconditions.checkNotNull(principalKeyBuffer, "principal key bytebuffer cannot be null");
+
+        Clause inPrincipal = QueryBuilder.eq("key", principalKeyBuffer);
+        Statement statement = QueryBuilder
+            .select()
+            .column("column1")
+            .from(PRINCIPAL_TOKENS_TABLE)
+            .where(inPrincipal);
+
+        final List<Row> rows = session.execute(statement).all();
+        final List<UUID> tokenUUIDs = new ArrayList<>(rows.size());
+
+        rows.forEach(row -> tokenUUIDs.add(row.getUUID("column1")));
+
+        return tokenUUIDs;
     }
 
 
@@ -219,13 +354,32 @@ public class TokenSerializationImpl implements TokenSerialization {
             case TOKEN_UUID:
                 return DataType.uuid().deserialize(bb, ProtocolVersion.NEWEST_SUPPORTED);
             case TOKEN_STATE:
-                fromByteBuffer(bb, Object.class);
+                return fromByteBuffer(bb, Object.class);
         }
 
         return null;
     }
 
 
+    private ByteBuffer toByteBuffer( Object obj ) {
+        if ( obj == null ) {
+            return null;
+        }
+
+        byte[] bytes = null;
+        try {
+            bytes = smileMapper.writeValueAsBytes( obj );
+        }
+        catch ( Exception e ) {
+            logger.error( "Error getting SMILE bytes", e );
+        }
+        if ( bytes != null ) {
+            return ByteBuffer.wrap( bytes );
+        }
+        return null;
+    }
+
+
     private Object fromByteBuffer( ByteBuffer byteBuffer, Class<?> clazz ) {
         if ( ( byteBuffer == null ) || !byteBuffer.hasRemaining() ) {
             return null;
@@ -245,183 +399,14 @@ public class TokenSerializationImpl implements TokenSerialization {
         return obj;
     }
 
-//    @Override
-//    public V readValue(CacheScope scope, K key, TypeReference typeRef ) {
-//
-//        return readValueCQL( scope, key, typeRef);
-//
-//    }
-
-
-//    private V readValueCQL(CacheScope scope, K key, TypeReference typeRef){
-//
-//        Preconditions.checkNotNull(scope, "scope is required");
-//        Preconditions.checkNotNull(key, "key is required");
-//
-//        final String rowKeyString = scope.getApplication().getUuid().toString();
-//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
-//
-//        // determine column name based on K key to string
-//        final String columnName = key.toString();
-//
-//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
-//        final Clause inColumn = QueryBuilder.eq("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED) );
-//
-//        final Statement statement = QueryBuilder.select().all().from(TOKENS_TABLE)
-//            .where(inKey)
-//            .and(inColumn)
-//            .setConsistencyLevel(cassandraConfig.getDataStaxReadCl());
-//
-//        final ResultSet resultSet = session.execute(statement);
-//        final com.datastax.driver.core.Row row = resultSet.one();
-//
-//        if (row == null){
-//
-//            if(logger.isDebugEnabled()){
-//                logger.debug("Cache value not found for key {}", key );
-//            }
-//
-//            return null;
-//        }
-//
-//
-//        try {
-//
-//            return MAPPER.readValue(row.getBytes("value").array(), typeRef);
-//
-//        } catch (IOException ioe) {
-//            logger.error("Unable to read cached value", ioe);
-//            throw new RuntimeException("Unable to read cached value", ioe);
-//        }
-//
-//
-//    }
-
-
-//    @Override
-//    public V writeValue(CacheScope scope, K key, V value, Integer ttl) {
-//
-//        return writeValueCQL( scope, key, value, ttl);
-//
-//    }
-//
-//    private V writeValueCQL(CacheScope scope, K key, V value, Integer ttl) {
-//
-//        Preconditions.checkNotNull( scope, "scope is required");
-//        Preconditions.checkNotNull( key, "key is required" );
-//        Preconditions.checkNotNull( value, "value is required");
-//        Preconditions.checkNotNull( ttl, "ttl is required");
-//
-//
-//        final String rowKeyString = scope.getApplication().getUuid().toString();
-//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
-//
-//        // determine column name based on K key to string
-//        final String columnName = key.toString();
-//
-//        // serialize cache item
-//        byte[] cacheBytes;
-//        try {
-//            cacheBytes = MAPPER.writeValueAsBytes(value);
-//        } catch (JsonProcessingException jpe) {
-//            throw new RuntimeException("Unable to serialize cache value", jpe);
-//        }
-//
-//        final Using timeToLive = QueryBuilder.ttl(ttl);
-//
-//
-//        // convert to ByteBuffer for the blob DataType in Cassandra
-//        final ByteBuffer bb = ByteBuffer.allocate(cacheBytes.length);
-//        bb.put(cacheBytes);
-//        bb.flip();
-//
-//        final Statement cacheEntry = QueryBuilder.insertInto(TOKENS_TABLE)
-//            .using(timeToLive)
-//            .value("key", getPartitionKey(scope, rowKeyString, bucket))
-//            .value("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED))
-//            .value("value", bb);
-//
-//
-//        session.execute(cacheEntry);
-//
-//        logger.debug("Wrote cache item to scope {}\n   key/value types {}/{}\n   key:value: {}:{}",
-//            scope.getApplication().getUuid(),
-//            key.getClass().getSimpleName(),
-//            value.getClass().getSimpleName(),
-//            key,
-//            value);
-//
-//        return value;
-//
-//    }
-//
-//
-//
-//    @Override
-//    public void removeValue(CacheScope scope, K key) {
-//
-//        removeValueCQL(scope, key);
-//
-//    }
-//
-//
-//    private void removeValueCQL(CacheScope scope, K key) {
-//
-//        Preconditions.checkNotNull( scope, "scope is required");
-//        Preconditions.checkNotNull( key, "key is required" );
-//
-//        // determine bucketed row-key based application UUID
-//
-//        final String rowKeyString = scope.getApplication().getUuid().toString();
-//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
-//
-//        // determine column name based on K key to string
-//        final String columnName = key.toString();
-//
-//
-//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
-//        final Clause inColumn = QueryBuilder.eq("column1", DataType.text().serialize(columnName, ProtocolVersion.NEWEST_SUPPORTED) );
-//
-//        final Statement statement = QueryBuilder.delete().from(TOKENS_TABLE)
-//            .where(inKey)
-//            .and(inColumn);
-//
-//        session.execute(statement);
-//
-//    }
-//
-//
-//    @Override
-//    public void invalidate(CacheScope scope) {
-//
-//        invalidateCQL(scope);
-//        logger.debug("Invalidated scope {}", scope.getApplication().getUuid());
-//
-//    }
-//
-//    private void invalidateCQL(CacheScope scope){
-//
-//        Preconditions.checkNotNull(scope, "scope is required");
-//
-//        // determine bucketed row-key based application UUID
-//        final String rowKeyString = scope.getApplication().getUuid().toString();
-//        final int bucket = BUCKET_LOCATOR.getCurrentBucket(rowKeyString);
-//
-//        final Clause inKey = QueryBuilder.eq("key", getPartitionKey(scope, rowKeyString, bucket) );
-//
-//        final Statement statement = QueryBuilder.delete().from(TOKENS_TABLE)
-//            .where(inKey);
-//
-//        session.execute(statement);
-//
-//    }
-//
+
     @Override
     public Collection<MultiTenantColumnFamilyDefinition> getColumnFamilies() {
 
         return Collections.emptyList();
     }
 
+
     @Override
     public Collection<TableDefinition> getTables() {
 
@@ -447,90 +432,5 @@ public class TokenSerializationImpl implements TokenSerialization {
 
         return Arrays.asList(tokens, principalTokens);
     }
-//
-//
-//
-//    private ByteBuffer getPartitionKey(CacheScope scope, String key, int bucketNumber){
-//
-//        return serializeKeys(scope.getApplication().getUuid(),
-//            scope.getApplication().getType(), bucketNumber, key);
-//
-//    }
-
-    private static ByteBuffer serializeTokenKey(UUID ownerUUID, String ownerType, int bucketNumber, String rowKeyString ){
-
-        List<Object> keys = new ArrayList<>(4);
-        keys.add(0, ownerUUID);
-        keys.add(1, ownerType);
-        keys.add(2, bucketNumber);
-        keys.add(3, rowKeyString);
-
-        // UUIDs are 16 bytes, allocate the buffer accordingly
-        int size = 16+ownerType.getBytes().length+rowKeyString.getBytes().length;
-
-        // ints are 4 bytes, add for the bucket
-        size += 4;
-
-
-        // we always need to add length for the 2 byte short and 1 byte equality
-        size += keys.size()*3;
-
-        ByteBuffer stuff = ByteBuffer.allocate(size);
-
-        for (Object key : keys) {
-
-            ByteBuffer kb = DataType.serializeValue(key, ProtocolVersion.NEWEST_SUPPORTED);
-            if (kb == null) {
-                kb = ByteBuffer.allocate(0);
-            }
-
-            stuff.putShort((short) kb.remaining());
-            stuff.put(kb.slice());
-            stuff.put((byte) 0);
-
-
-        }
-        stuff.flip();
-        return stuff;
-
-    }
-
-    private static ByteBuffer serializeKeys(UUID ownerUUID, String ownerType, int bucketNumber, String rowKeyString ){
-
-        List<Object> keys = new ArrayList<>(4);
-        keys.add(0, ownerUUID);
-        keys.add(1, ownerType);
-        keys.add(2, bucketNumber);
-        keys.add(3, rowKeyString);
-
-        // UUIDs are 16 bytes, allocate the buffer accordingly
-        int size = 16+ownerType.getBytes().length+rowKeyString.getBytes().length;
-
-        // ints are 4 bytes, add for the bucket
-        size += 4;
-
-
-        // we always need to add length for the 2 byte short and 1 byte equality
-        size += keys.size()*3;
-
-        ByteBuffer stuff = ByteBuffer.allocate(size);
-
-        for (Object key : keys) {
-
-            ByteBuffer kb = DataType.serializeValue(key, ProtocolVersion.NEWEST_SUPPORTED);
-            if (kb == null) {
-                kb = ByteBuffer.allocate(0);
-            }
-
-            stuff.putShort((short) kb.remaining());
-            stuff.put(kb.slice());
-            stuff.put((byte) 0);
-
-
-        }
-        stuff.flip();
-        return stuff;
-
-    }
 
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TestTokenModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TestTokenModule.java b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TestTokenModule.java
new file mode 100644
index 0000000..bfa0aa0
--- /dev/null
+++ b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TestTokenModule.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.usergrid.persistence.token;
+
+
+import org.apache.usergrid.persistence.token.guice.TokenModule;
+import org.apache.usergrid.persistence.token.impl.TokenSerializationImpl;
+import org.apache.usergrid.persistence.core.guice.CommonModule;
+
+
+
+public class TestTokenModule extends org.apache.usergrid.persistence.core.guice.TestModule {
+
+    @Override
+    protected void configure() {
+
+        install( new CommonModule() );
+        install( new TokenModule() );
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenSerializationTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenSerializationTest.java b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenSerializationTest.java
new file mode 100644
index 0000000..7beeb56
--- /dev/null
+++ b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenSerializationTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.usergrid.persistence.token;
+
+import net.jcip.annotations.NotThreadSafe;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+import org.apache.usergrid.persistence.token.impl.TokenSerializationImpl;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.apache.usergrid.persistence.core.guice.MigrationManagerRule;
+import org.apache.usergrid.persistence.core.test.ITRunner;
+import org.apache.usergrid.persistence.core.test.UseModules;
+
+import com.google.inject.Inject;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+
+
+@RunWith( ITRunner.class )
+@UseModules( { TestTokenModule.class } )
+@NotThreadSafe
+public class TokenSerializationTest {
+
+
+    @Inject
+    @Rule
+    public MigrationManagerRule migrationManagerRule;
+
+    @Inject
+    public TokenSerialization tokenSerialization;
+
+    @Test
+    public void putTokenInfo() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap("test-principal".getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+    }
+
+    @Test
+    public void getTokenInfo() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap("test-principal".getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+        Map<String, Object> returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            tokenDetails.get(TokenSerializationImpl.TOKEN_TYPE),
+            returnedDetails.get(TokenSerializationImpl.TOKEN_TYPE)
+        );
+    }
+
+    @Test
+    public void updateAccessTokenTime() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        long accessedTime = System.currentTimeMillis()-1000000;
+        long inactiveTime = accessedTime+2000000;
+
+        tokenDetails.put(TokenSerializationImpl.TOKEN_ACCESSED, accessedTime);
+        tokenDetails.put(TokenSerializationImpl.TOKEN_INACTIVE, inactiveTime);
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap("test-principal".getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+        Map<String, Object> returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            accessedTime,
+            returnedDetails.get(TokenSerializationImpl.TOKEN_ACCESSED)
+        );
+
+        long newAccessedTime = System.currentTimeMillis();
+        long newInactiveTime = newAccessedTime+1000000;
+
+        tokenSerialization.updateTokenAccessTime(uuid, newAccessedTime,newInactiveTime, 1200);
+
+        returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            newAccessedTime,
+            returnedDetails.get(TokenSerializationImpl.TOKEN_ACCESSED)
+        );
+    }
+
+    @Test
+    public void deleteTokens() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap("test-principal".getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+        Map<String, Object> returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            tokenDetails.get(TokenSerializationImpl.TOKEN_TYPE),
+            returnedDetails.get(TokenSerializationImpl.TOKEN_TYPE)
+        );
+
+        tokenSerialization.deleteTokens(Collections.singletonList(uuid), principalKeyBuffer);
+
+        returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            0,
+            returnedDetails.size()
+        );
+    }
+
+    @Test
+    public void revokeToken() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap("test-principal".getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+        Map<String, Object> returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            tokenDetails.get(TokenSerializationImpl.TOKEN_TYPE),
+            returnedDetails.get(TokenSerializationImpl.TOKEN_TYPE)
+        );
+
+        tokenSerialization.revokeToken(uuid, principalKeyBuffer);
+
+        returnedDetails = tokenSerialization.getTokenInfo(uuid);
+
+        assertEquals(
+            0,
+            returnedDetails.size()
+        );
+    }
+
+    @Test
+    public void getTokensForPrincipal() {
+
+        UUID uuid = UUIDGenerator.newTimeUUID();
+        Map<String, Object> tokenDetails = new HashMap<>();
+        tokenDetails.put(TokenSerializationImpl.TOKEN_TYPE, "test-token");
+
+        String principal = "test-principal-"+System.currentTimeMillis();
+
+        ByteBuffer principalKeyBuffer = ByteBuffer.wrap(principal.getBytes());
+
+        tokenSerialization.putTokenInfo(uuid, tokenDetails, principalKeyBuffer, 60);
+
+        principalKeyBuffer = ByteBuffer.wrap(principal.getBytes());
+
+        List<UUID> returnTokens = tokenSerialization.getTokensForPrincipal(principalKeyBuffer);
+
+        assertEquals(
+            returnTokens.get(0),
+            uuid
+        );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java b/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
deleted file mode 100644
index b454d73..0000000
--- a/stack/corepersistence/token/src/test/java/org/apache/usergrid/persistence/token/TokenTestModule.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.usergrid.persistence.token;
-
-
-import org.apache.usergrid.persistence.token.guice.TokenModule;
-import org.apache.usergrid.persistence.token.impl.TokenSerialization;
-import org.apache.usergrid.persistence.token.impl.TokenSerializationImpl;
-import org.apache.usergrid.persistence.core.guice.CommonModule;
-
-
-
-public class TokenTestModule extends org.apache.usergrid.persistence.core.guice.TestModule {
-
-    @Override
-    protected void configure() {
-
-        install( new CommonModule() );
-        install( new TokenModule() );
-
-        bind(TokenSerialization.class).to(TokenSerializationImpl.class).asEagerSingleton();
-    }
-}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/launcher/src/main/resources/usergrid-standalone.properties
----------------------------------------------------------------------
diff --git a/stack/launcher/src/main/resources/usergrid-standalone.properties b/stack/launcher/src/main/resources/usergrid-standalone.properties
index 03d9b80..cd014e6 100644
--- a/stack/launcher/src/main/resources/usergrid-standalone.properties
+++ b/stack/launcher/src/main/resources/usergrid-standalone.properties
@@ -63,8 +63,6 @@ usergrid.version.properties=1.0.0
 usergrid.version.build=${version}
 
 #usergrid.auth.token_secret_salt=super secret token value
-#usergrid.auth.token_expires_from_last_use=false
-#usergrid.auth.token_refresh_reuses_id=false
 
 # max time to persist tokens for (milliseconds)
 #usergrid.auth.token.persist.expires=0

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
index 12e1270..48aec78 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
@@ -41,7 +41,7 @@ import org.apache.usergrid.security.shiro.utils.SubjectUtils;
 import org.apache.usergrid.security.sso.ApigeeSSO2Provider;
 import org.apache.usergrid.security.sso.ExternalSSOProvider;
 import org.apache.usergrid.security.sso.SSOProviderFactory;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
 import org.apache.usergrid.utils.JsonUtils;
 import org.glassfish.jersey.server.mvc.Viewable;
@@ -62,7 +62,7 @@ import java.util.Map;
 import static javax.servlet.http.HttpServletResponse.*;
 import static javax.ws.rs.core.MediaType.*;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
-import static org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl.USERGRID_EXTERNAL_SSO_ENABLED;
+import static org.apache.usergrid.security.tokens.impl.TokenServiceImpl.USERGRID_EXTERNAL_SSO_ENABLED;
 import static org.apache.usergrid.utils.JsonUtils.mapToJsonString;
 import static org.apache.usergrid.utils.StringUtils.stringOrSubstringAfterFirst;
 import static org.apache.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
index 066f734..4cbe9b2 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
@@ -30,7 +30,7 @@ import org.apache.usergrid.rest.management.users.organizations.OrganizationsReso
 import org.apache.usergrid.rest.security.annotations.RequireAdminUserAccess;
 import org.apache.usergrid.security.shiro.principals.PrincipalIdentifier;
 import org.apache.usergrid.security.tokens.TokenInfo;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.apache.usergrid.security.tokens.exceptions.TokenException;
 import org.apache.usergrid.services.ServiceResults;
 import org.glassfish.jersey.server.mvc.Viewable;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UsersResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UsersResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UsersResource.java
index 6999841..634e5da 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UsersResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UsersResource.java
@@ -29,7 +29,7 @@ import org.apache.usergrid.rest.RootResource;
 import org.apache.usergrid.rest.exceptions.AuthErrorInfo;
 import org.apache.usergrid.rest.exceptions.RedirectionException;
 import org.apache.usergrid.security.shiro.utils.SubjectUtils;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.glassfish.jersey.server.mvc.Viewable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,7 +46,6 @@ import java.util.UUID;
 import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.apache.usergrid.rest.exceptions.SecurityException.mappableSecurityException;
 import static org.apache.usergrid.security.shiro.utils.SubjectUtils.isServiceAdmin;
-import static org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl.USERGRID_EXTERNAL_SSO_PROVIDER_URL;
 
 
 @Component( "org.apache.usergrid.rest.management.users.UsersResource" )

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
index 0a80d73..8d18521f 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
@@ -25,7 +25,7 @@ import org.apache.usergrid.rest.management.organizations.OrganizationsResource;
 import org.apache.usergrid.rest.test.resource.AbstractRestIT;
 import org.apache.usergrid.rest.test.resource.model.*;
 import org.apache.usergrid.rest.test.resource.model.Collection;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -38,9 +38,9 @@ import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.util.*;
 
-import static org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl.USERGRID_EXTERNAL_SSO_PROVIDER;
-import static org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl.USERGRID_EXTERNAL_SSO_PROVIDER_URL;
-import static org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl.USERGRID_EXTERNAL_SSO_ENABLED;
+import static org.apache.usergrid.security.tokens.impl.TokenServiceImpl.USERGRID_EXTERNAL_SSO_PROVIDER;
+import static org.apache.usergrid.security.tokens.impl.TokenServiceImpl.USERGRID_EXTERNAL_SSO_PROVIDER_URL;
+import static org.apache.usergrid.security.tokens.impl.TokenServiceImpl.USERGRID_EXTERNAL_SSO_ENABLED;
 import static org.apache.usergrid.utils.MapUtils.hashMap;
 import static org.junit.Assert.*;
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/services/src/main/java/org/apache/usergrid/security/sso/SSOProviderFactory.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/sso/SSOProviderFactory.java b/stack/services/src/main/java/org/apache/usergrid/security/sso/SSOProviderFactory.java
index 31e085e..b723d9e 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/sso/SSOProviderFactory.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/sso/SSOProviderFactory.java
@@ -18,7 +18,7 @@ package org.apache.usergrid.security.sso;
 
 import org.apache.usergrid.corepersistence.CpEntityManagerFactory;
 import org.apache.usergrid.persistence.EntityManagerFactory;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.List;


[2/7] usergrid git commit: Finish convert token service persistence to Datastax. Add tests, and rename the package for TokenServiceImpl to impl from cassandra.

Posted by mr...@apache.org.
http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
deleted file mode 100644
index 6ea6de0..0000000
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
+++ /dev/null
@@ -1,848 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.usergrid.security.tokens.cassandra;
-
-
-import com.google.inject.Injector;
-import me.prettyprint.hector.api.Keyspace;
-import me.prettyprint.hector.api.beans.HColumn;
-import me.prettyprint.hector.api.mutation.Mutator;
-import org.apache.usergrid.corepersistence.CpEntityManagerFactory;
-import org.apache.usergrid.corepersistence.util.CpNamingUtils;
-import org.apache.usergrid.management.ApplicationCreator;
-import org.apache.usergrid.management.ManagementService;
-import org.apache.usergrid.management.UserInfo;
-import org.apache.usergrid.persistence.EntityManagerFactory;
-import org.apache.usergrid.persistence.cassandra.CassandraService;
-import org.apache.usergrid.persistence.core.metrics.MetricsFactory;
-import org.apache.usergrid.persistence.entities.Application;
-import org.apache.usergrid.security.AuthPrincipalInfo;
-import org.apache.usergrid.security.AuthPrincipalType;
-import org.apache.usergrid.security.sso.SSOProviderFactory;
-import org.apache.usergrid.security.tokens.TokenCategory;
-import org.apache.usergrid.security.tokens.TokenInfo;
-import org.apache.usergrid.security.tokens.TokenService;
-import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
-import org.apache.usergrid.security.tokens.exceptions.ExpiredTokenException;
-import org.apache.usergrid.security.tokens.exceptions.InvalidTokenException;
-import org.apache.usergrid.security.sso.ExternalSSOProvider;
-import org.apache.usergrid.utils.ConversionUtils;
-import org.apache.usergrid.utils.JsonUtils;
-import org.apache.usergrid.utils.UUIDUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.util.Assert;
-
-import javax.ws.rs.client.Client;
-import java.nio.ByteBuffer;
-import java.util.*;
-
-import static java.lang.System.currentTimeMillis;
-import static me.prettyprint.hector.api.factory.HFactory.createColumn;
-import static me.prettyprint.hector.api.factory.HFactory.createMutator;
-import static org.apache.commons.codec.binary.Base64.decodeBase64;
-import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
-import static org.apache.commons.codec.digest.DigestUtils.sha;
-import static org.apache.usergrid.persistence.cassandra.CassandraPersistenceUtils.getColumnMap;
-import static org.apache.usergrid.persistence.cassandra.CassandraService.PRINCIPAL_TOKEN_CF;
-import static org.apache.usergrid.persistence.cassandra.CassandraService.TOKENS_CF;
-import static org.apache.usergrid.persistence.cassandra.Serializers.*;
-import static org.apache.usergrid.security.AuthPrincipalType.ADMIN_USER;
-import static org.apache.usergrid.security.tokens.TokenCategory.*;
-import static org.apache.usergrid.utils.ConversionUtils.*;
-import static org.apache.usergrid.utils.MapUtils.hasKeys;
-import static org.apache.usergrid.utils.MapUtils.hashMap;
-import static org.apache.usergrid.utils.UUIDUtils.getTimestampInMillis;
-
-
-public class TokenServiceImpl implements TokenService {
-
-    private static final Logger logger = LoggerFactory.getLogger( TokenServiceImpl.class );
-
-    public static final String PROPERTIES_AUTH_TOKEN_SECRET_SALT = "usergrid.auth.token_secret_salt";
-    public static final String PROPERTIES_AUTH_TOKEN_EXPIRES_FROM_LAST_USE =
-            "usergrid.auth.token_expires_from_last_use";
-    public static final String PROPERTIES_AUTH_TOKEN_REFRESH_REUSES_ID = "usergrid.auth.token_refresh_reuses_id";
-
-    private static final String TOKEN_UUID = "uuid";
-    private static final String TOKEN_TYPE = "type";
-    private static final String TOKEN_CREATED = "created";
-    private static final String TOKEN_ACCESSED = "accessed";
-    private static final String TOKEN_INACTIVE = "inactive";
-    private static final String TOKEN_DURATION = "duration";
-    private static final String TOKEN_PRINCIPAL_TYPE = "principal";
-    private static final String TOKEN_ENTITY = "entity";
-    private static final String TOKEN_APPLICATION = "application";
-    private static final String TOKEN_STATE = "state";
-    private static final String TOKEN_WORKFLOW_ORG_ID = "workflowOrgId";
-
-
-    private static final String TOKEN_TYPE_ACCESS = "access";
-
-
-    private static final Set<String> TOKEN_PROPERTIES;
-
-
-    static {
-        HashSet<String> set = new HashSet<String>();
-        set.add( TOKEN_UUID );
-        set.add( TOKEN_TYPE );
-        set.add( TOKEN_CREATED );
-        set.add( TOKEN_ACCESSED );
-        set.add( TOKEN_INACTIVE );
-        set.add( TOKEN_PRINCIPAL_TYPE );
-        set.add( TOKEN_ENTITY );
-        set.add( TOKEN_APPLICATION );
-        set.add( TOKEN_STATE );
-        set.add( TOKEN_DURATION );
-        set.add( TOKEN_WORKFLOW_ORG_ID );
-        TOKEN_PROPERTIES = Collections.unmodifiableSet(set);
-    }
-
-
-    private static final HashSet<String> REQUIRED_TOKEN_PROPERTIES = new HashSet<String>();
-
-
-    static {
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_UUID );
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_TYPE );
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_CREATED );
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_ACCESSED );
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_INACTIVE );
-        REQUIRED_TOKEN_PROPERTIES.add( TOKEN_DURATION );
-    }
-
-
-    public static final String TOKEN_SECRET_SALT = "super secret token value";
-
-    // Short-lived token is good for 24 hours
-    public static final long SHORT_TOKEN_AGE = 24 * 60 * 60 * 1000;
-
-    // Long-lived token is good for 7 days
-    public static final long LONG_TOKEN_AGE = 7 * 24 * 60 * 60 * 1000;
-
-    String tokenSecretSalt = TOKEN_SECRET_SALT;
-
-    long maxPersistenceTokenAge = LONG_TOKEN_AGE;
-
-    Map<TokenCategory, Long> tokenExpirations =
-            hashMap( ACCESS, LONG_TOKEN_AGE ).map( REFRESH, LONG_TOKEN_AGE ).map( EMAIL, LONG_TOKEN_AGE )
-                    .map( OFFLINE, LONG_TOKEN_AGE );
-
-    long maxAccessTokenAge = SHORT_TOKEN_AGE;
-    long maxRefreshTokenAge = LONG_TOKEN_AGE;
-    long maxEmailTokenAge = LONG_TOKEN_AGE;
-    long maxOfflineTokenAge = LONG_TOKEN_AGE;
-
-    protected CassandraService cassandra;
-
-    protected Properties properties;
-
-    protected EntityManagerFactory emf;
-
-    protected MetricsFactory metricsFactory;
-
-
-    public TokenServiceImpl() {
-    }
-
-
-    long getExpirationProperty( String name, long default_expiration ) {
-        long expires = Long.parseLong(
-                properties.getProperty( "usergrid.auth.token." + name + ".expires", "" + default_expiration ) );
-        return expires > 0 ? expires : default_expiration;
-    }
-
-
-    long getExpirationForTokenType( TokenCategory tokenCategory ) {
-        Long l = tokenExpirations.get( tokenCategory );
-        if ( l != null ) {
-            return l;
-        }
-        return SHORT_TOKEN_AGE;
-    }
-
-
-    void setExpirationFromProperties( String name ) {
-        TokenCategory tokenCategory = TokenCategory.valueOf( name.toUpperCase() );
-        long expires = Long.parseLong( properties.getProperty( "usergrid.auth.token." + name + ".expires",
-                "" + getExpirationForTokenType( tokenCategory ) ) );
-        if ( expires > 0 ) {
-            tokenExpirations.put( tokenCategory, expires );
-        }
-        logger.info( "{} token expires after {} seconds", name, getExpirationForTokenType( tokenCategory ) / 1000 );
-    }
-
-
-    @Autowired
-    public void setProperties( Properties properties ) {
-        this.properties = properties;
-
-        if ( properties != null ) {
-            maxPersistenceTokenAge = getExpirationProperty( "persistence", maxPersistenceTokenAge );
-
-            setExpirationFromProperties( "access" );
-            setExpirationFromProperties( "refresh" );
-            setExpirationFromProperties( "email" );
-            setExpirationFromProperties( "offline" );
-
-            tokenSecretSalt = properties.getProperty( PROPERTIES_AUTH_TOKEN_SECRET_SALT, TOKEN_SECRET_SALT );
-        }
-    }
-
-
-    @Override
-    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
-                               Map<String, Object> state, long duration ) throws Exception {
-        return createToken( tokenCategory, type, principal, state, duration, null, System.currentTimeMillis() );
-    }
-
-
-    @Override
-    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
-                               Map<String, Object> state, long duration, UUID workflowOrgId ) throws Exception {
-        return createToken( tokenCategory, type, principal, state, duration, workflowOrgId, System.currentTimeMillis() );
-    }
-
-
-    /** Exposed for testing purposes. The interface does not allow creation timestamp checking */
-    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
-                               Map<String, Object> state, long duration, UUID workflowOrgId,
-                               long creationTimestamp ) throws Exception {
-
-        long maxTokenTtl = getMaxTtl( tokenCategory, principal );
-
-        if ( duration > maxTokenTtl ) {
-            throw new IllegalArgumentException(
-                    String.format( "Your token age cannot be more than the maximum age of %d milliseconds",
-                            maxTokenTtl ) );
-        }
-
-        if ( duration == 0 ) {
-            duration = maxTokenTtl;
-        }
-
-        if ( principal != null ) {
-            Assert.notNull( principal.getType() );
-            Assert.notNull( principal.getApplicationId() );
-            Assert.notNull( principal.getUuid() );
-        }
-
-        // create UUID that we will use to store token info in our database
-        UUID uuid = UUIDUtils.newTimeUUID( creationTimestamp );
-
-        long timestamp = getTimestampInMillis( uuid );
-        if ( type == null ) {
-            type = TOKEN_TYPE_ACCESS;
-        }
-        TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration, principal,
-                state, workflowOrgId );
-        putTokenInfo( tokenInfo );
-
-        // generate token from the UUID that we created
-        return getTokenForUUID(tokenInfo, tokenCategory, uuid);
-    }
-
-
-    @Override
-    public void importToken(String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
-                            Map<String, Object> state, long duration) throws Exception {
-
-        importToken(token, tokenCategory, type, principal, state, duration, null);
-    }
-
-
-    @Override
-    public void importToken(String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
-                            Map<String, Object> state, long duration, UUID workflowOrgId) throws Exception {
-
-        // same logic as create token
-
-        long maxTokenTtl = getMaxTtl( tokenCategory, principal );
-
-        if ( duration > maxTokenTtl ) {
-            throw new IllegalArgumentException(
-                    String.format( "Your token age cannot be more than the maximum age of %d milliseconds",
-                            maxTokenTtl ) );
-        }
-
-        if ( duration == 0 ) {
-            duration = maxTokenTtl;
-        }
-
-        if ( principal != null ) {
-            Assert.notNull( principal.getType() );
-            Assert.notNull( principal.getApplicationId() );
-            Assert.notNull( principal.getUuid() );
-        }
-
-        // except that we generate the UUID based on the token
-
-        UUID uuid = getUUIDForToken(token);
-
-        long timestamp = getTimestampInMillis( uuid );
-        if ( type == null ) {
-            type = TOKEN_TYPE_ACCESS;
-        }
-
-        TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration, principal,
-                state, workflowOrgId );
-        putTokenInfo( tokenInfo );
-    }
-
-
-    @Override
-    public TokenInfo getTokenInfo( String token ) throws Exception {
-        return getTokenInfo(token, true);
-    }
-
-
-    @Override
-    public TokenInfo getTokenInfo( String token, boolean updateAccessTime ) throws Exception {
-
-        UUID uuid;
-
-
-        /** Pre-validation of the token string based on Usergrid's encoding scheme.
-         *
-         * If the token does not parse out a UUID, then it's not a Usergrid token.  Check if External SSO provider
-         * is configured, which is not Usergrid and immediately try to validate the token based on this parsing
-         * information.
-         */
-        try{
-            uuid = getUUIDForToken( token );
-        }
-        catch (ExpiredTokenException expiredTokenException){
-            throw new ExpiredTokenException(expiredTokenException.getMessage());
-        }
-        catch(Exception e){
-
-            // If the token doesn't parse as a Usergrid token, see if an external provider other than Usergrid is
-            // enabled.  If so, just validate the external token.
-            try{
-                if( isExternalSSOProviderEnabled() && !getExternalSSOProvider().equalsIgnoreCase("usergrid")) {
-                    return validateExternalToken(token, 1, getExternalSSOProvider());
-                }else{
-                    throw new IllegalArgumentException("invalid external provider : " + getExternalSSOProvider()); // re-throw the error
-                }
-            }
-            catch (NullPointerException npe){
-                throw new IllegalArgumentException("The SSO provider in the config is empty.");
-            }
-
-        }
-
-        final TokenInfo tokenInfo;
-
-        /**
-         * Now try actual Usergrid token validations.  First try locally.  If that fails and SSO is enabled with
-         * Usergrid being a provider, validate the external token.
-         */
-        try {
-            tokenInfo = getTokenInfo( uuid );
-        } catch (InvalidTokenException e){
-            // Try the request from Usergrid, conditions are specific so we don't incur perf hits for unncessary
-            // token validations that are known to not
-            if ( isExternalSSOProviderEnabled() && getExternalSSOProvider().equalsIgnoreCase("usergrid") ){
-                return validateExternalToken( token, maxPersistenceTokenAge, getExternalSSOProvider() );
-            }else{
-                throw e; // re-throw the error
-            }
-        }
-
-        if (updateAccessTime) {
-            //update the token
-            long now = currentTimeMillis();
-
-            long maxTokenTtl = getMaxTtl(TokenCategory.getFromBase64String(token), tokenInfo.getPrincipal());
-
-            Mutator<UUID> batch = createMutator(cassandra.getUsergridApplicationKeyspace(), ue);
-
-            HColumn<String, Long> col =
-                    createColumn(TOKEN_ACCESSED, now, calcTokenTime(tokenInfo.getExpiration(maxTokenTtl)),
-                            se, le);
-            batch.addInsertion(uuid, TOKENS_CF, col);
-
-            long inactive = now - tokenInfo.getAccessed();
-            if (inactive > tokenInfo.getInactive()) {
-                col = createColumn(TOKEN_INACTIVE, inactive, calcTokenTime(tokenInfo.getExpiration(maxTokenTtl)),
-                        se, le);
-                batch.addInsertion(uuid, TOKENS_CF, col);
-                tokenInfo.setInactive(inactive);
-            }
-
-            batch.execute();
-        }
-
-        return tokenInfo;
-    }
-
-
-    /** Get the max ttl per app. This is null safe,and will return the default in the case of missing data */
-    private long getMaxTtl( TokenCategory tokenCategory, AuthPrincipalInfo principal ) throws Exception {
-
-        if ( principal == null ) {
-            return maxPersistenceTokenAge;
-        }
-        long defaultMaxTtlForTokenType = getExpirationForTokenType( tokenCategory );
-
-        Application application = emf.getEntityManager( principal.getApplicationId() )
-                                     .get( principal.getApplicationId(), Application.class );
-
-        if ( application == null ) {
-            return defaultMaxTtlForTokenType;
-        }
-
-        // set the max to the default
-        long maxTokenTtl = defaultMaxTtlForTokenType;
-
-        // it's been defined on the expiration, override it
-        if ( application.getAccesstokenttl() != null ) {
-            maxTokenTtl = application.getAccesstokenttl();
-
-            // it's set to 0 which equals infinity, set our expiration to
-            // LONG.MAX
-            if ( maxTokenTtl == 0 ) {
-                maxTokenTtl = Long.MAX_VALUE;
-            }
-        }
-
-        return maxTokenTtl;
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see
-     * org.apache.usergrid.security.tokens.TokenService#removeTokens(org.apache.usergrid.security
-     * .AuthPrincipalInfo)
-     */
-    @Override
-    public void removeTokens( AuthPrincipalInfo principal ) throws Exception {
-        List<UUID> tokenIds = getTokenUUIDS( principal );
-
-        Mutator<ByteBuffer> batch = createMutator( cassandra.getUsergridApplicationKeyspace(), be );
-
-        for ( UUID tokenId : tokenIds ) {
-            batch.addDeletion( bytebuffer( tokenId ), TOKENS_CF );
-        }
-
-        batch.addDeletion( principalKey( principal ), PRINCIPAL_TOKEN_CF );
-
-        batch.execute();
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see
-     * org.apache.usergrid.security.tokens.TokenService#revokeToken(java.lang.String)
-     */
-    @Override
-    public void revokeToken( String token ) {
-
-        TokenInfo info;
-
-        try {
-            info = getTokenInfo( token );
-        }
-        catch ( Exception e ) {
-            logger.error( "Unable to find token with the specified value ignoring request.  Value : {}", token );
-            return;
-        }
-
-        UUID tokenId = info.getUuid();
-
-        Mutator<ByteBuffer> batch = createMutator( cassandra.getUsergridApplicationKeyspace(), be );
-
-        // clean up the link in the principal -> token index if the principal is
-        // on the token
-        if ( info.getPrincipal() != null ) {
-            batch.addDeletion( principalKey( info.getPrincipal() ), PRINCIPAL_TOKEN_CF, bytebuffer( tokenId ),
-                    be );
-        }
-
-        // remove the token from the tokens cf
-        batch.addDeletion( bytebuffer( tokenId ), TOKENS_CF );
-
-        batch.execute();
-    }
-
-
-    private TokenInfo getTokenInfo( UUID uuid ) throws Exception {
-        if ( uuid == null ) {
-            throw new InvalidTokenException( "No token specified" );
-        }
-        Map<String, ByteBuffer> columns = getColumnMap( cassandra
-                .getColumns( cassandra.getUsergridApplicationKeyspace(), TOKENS_CF, uuid, TOKEN_PROPERTIES, se,
-                        be ) );
-        if ( !hasKeys( columns, REQUIRED_TOKEN_PROPERTIES ) ) {
-            throw new InvalidTokenException( "Token not found in database" );
-        }
-        String type = string( columns.get( TOKEN_TYPE ) );
-        long created = getLong( columns.get( TOKEN_CREATED ) );
-        long accessed = getLong( columns.get( TOKEN_ACCESSED ) );
-        long inactive = getLong( columns.get( TOKEN_INACTIVE ) );
-        long duration = getLong( columns.get( TOKEN_DURATION ) );
-        String principalTypeStr = string( columns.get( TOKEN_PRINCIPAL_TYPE ) );
-        AuthPrincipalType principalType = null;
-        if ( principalTypeStr != null ) {
-            try {
-                principalType = AuthPrincipalType.valueOf( principalTypeStr.toUpperCase() );
-            }
-            catch ( IllegalArgumentException e ) {
-            }
-        }
-        AuthPrincipalInfo principal = null;
-        if ( principalType != null ) {
-            UUID entityId = uuid( columns.get( TOKEN_ENTITY ) );
-            UUID appId = uuid( columns.get( TOKEN_APPLICATION ) );
-            principal = new AuthPrincipalInfo( principalType, entityId, appId );
-        }
-        @SuppressWarnings("unchecked") Map<String, Object> state =
-                ( Map<String, Object> ) JsonUtils.fromByteBuffer( columns.get( TOKEN_STATE ) );
-
-        UUID workflowOrgId = null;
-        if (columns.containsKey(TOKEN_WORKFLOW_ORG_ID)) {
-            workflowOrgId = ConversionUtils.uuid(columns.get(TOKEN_WORKFLOW_ORG_ID));
-        }
-
-        return new TokenInfo( uuid, type, created, accessed, inactive, duration, principal, state, workflowOrgId );
-    }
-
-
-    private void putTokenInfo( TokenInfo tokenInfo ) throws Exception {
-
-        ByteBuffer tokenUUID = bytebuffer( tokenInfo.getUuid() );
-
-        Keyspace ko = cassandra.getUsergridApplicationKeyspace();
-
-        Mutator<ByteBuffer> m = createMutator( ko, be );
-
-        int ttl = calcTokenTime( tokenInfo.getDuration() );
-
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_UUID, bytebuffer( tokenInfo.getUuid() ), ttl, se, be ) );
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_TYPE, bytebuffer( tokenInfo.getType() ), ttl, se, be ) );
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_CREATED, bytebuffer( tokenInfo.getCreated() ), ttl, se, be ) );
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_ACCESSED, bytebuffer( tokenInfo.getAccessed() ), ttl, se, be ) );
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_INACTIVE, bytebuffer( tokenInfo.getInactive() ), ttl, se, be ) );
-        m.addInsertion( tokenUUID, TOKENS_CF,
-                createColumn( TOKEN_DURATION, bytebuffer( tokenInfo.getDuration() ), ttl, se, be ) );
-
-        if ( tokenInfo.getPrincipal() != null ) {
-
-            AuthPrincipalInfo principalInfo = tokenInfo.getPrincipal();
-
-            m.addInsertion( tokenUUID, TOKENS_CF,
-                    createColumn( TOKEN_PRINCIPAL_TYPE, bytebuffer( principalInfo.getType().toString().toLowerCase() ),
-                            ttl, se, be ) );
-            m.addInsertion( tokenUUID, TOKENS_CF,
-                    createColumn( TOKEN_ENTITY, bytebuffer( principalInfo.getUuid() ), ttl, se, be ) );
-            m.addInsertion( tokenUUID, TOKENS_CF,
-                    createColumn( TOKEN_APPLICATION, bytebuffer( principalInfo.getApplicationId() ), ttl, se,
-                            be ) );
-
-      /*
-       * write to the PRINCIPAL+TOKEN The format is as follow
-       *
-       * appid+principalId+principalType :{ tokenuuid: 0x00}
-       */
-
-            ByteBuffer rowKey = principalKey( principalInfo );
-            m.addInsertion( rowKey, PRINCIPAL_TOKEN_CF, createColumn( tokenUUID, HOLDER, ttl, be, be ) );
-        }
-
-        if ( tokenInfo.getState() != null ) {
-            m.addInsertion( tokenUUID, TOKENS_CF,
-                    createColumn( TOKEN_STATE, JsonUtils.toByteBuffer( tokenInfo.getState() ), ttl, se,
-                            be ) );
-        }
-
-        if ( tokenInfo.getWorkflowOrgId() != null ) {
-            m.addInsertion( tokenUUID, TOKENS_CF,
-                    createColumn( TOKEN_WORKFLOW_ORG_ID, bytebuffer( tokenInfo.getWorkflowOrgId() ), ttl, se, be ) );
-        }
-
-        m.execute();
-    }
-
-
-    /** Load all the token uuids for a principal info */
-    private List<UUID> getTokenUUIDS( AuthPrincipalInfo principal ) throws Exception {
-
-        ByteBuffer rowKey = principalKey( principal );
-
-        List<HColumn<ByteBuffer, ByteBuffer>> cols = cassandra
-                .getColumns( cassandra.getUsergridApplicationKeyspace(), PRINCIPAL_TOKEN_CF, rowKey, null, null, Integer.MAX_VALUE,
-                        false );
-
-        List<UUID> results = new ArrayList<UUID>( cols.size() );
-
-        for ( HColumn<ByteBuffer, ByteBuffer> col : cols ) {
-            results.add( uuid( col.getName() ) );
-        }
-
-        return results;
-    }
-
-
-    private ByteBuffer principalKey( AuthPrincipalInfo principalInfo ) {
-        // 66 bytes, 2 UUIDS + 2 chars for prefix
-        ByteBuffer buff = ByteBuffer.allocate( 32 * 2 + 2 );
-        buff.put( bytes( principalInfo.getApplicationId() ) );
-        buff.put( bytes( principalInfo.getUuid() ) );
-        buff.put( bytes( principalInfo.getType().getPrefix() ) );
-        buff.rewind();
-
-        return buff;
-    }
-
-
-    private UUID getUUIDForToken(String token ) throws ExpiredTokenException, BadTokenException {
-        TokenCategory tokenCategory = TokenCategory.getFromBase64String( token );
-        byte[] bytes = decodeBase64( token.substring( TokenCategory.BASE64_PREFIX_LENGTH ) );
-        UUID uuid = uuid( bytes );
-        int i = 16;
-        long expires = Long.MAX_VALUE;
-        if ( tokenCategory.getExpires() ) {
-            expires = ByteBuffer.wrap( bytes, i, 8 ).getLong();
-            i = 24;
-        }
-        ByteBuffer expected = ByteBuffer.allocate( 20 );
-        expected.put( sha( tokenCategory.getPrefix() + uuid + tokenSecretSalt + expires ) );
-        expected.rewind();
-        ByteBuffer signature = ByteBuffer.wrap( bytes, i, 20 );
-
-
-        if ( !signature.equals( expected ) ) {
-            throw new BadTokenException( "Invalid token signature" );
-        }
-
-
-        long expirationDelta = System.currentTimeMillis() - expires;
-
-        if ( expires != Long.MAX_VALUE && expirationDelta > 0 ) {
-            throw new ExpiredTokenException( String.format( "Token expired %d milliseconds ago.", expirationDelta ) );
-        }
-        return uuid;
-    }
-
-
-    @Override
-    public long getMaxTokenAge( String token ) {
-        TokenCategory tokenCategory = TokenCategory.getFromBase64String( token );
-        byte[] bytes = decodeBase64( token.substring( TokenCategory.BASE64_PREFIX_LENGTH ) );
-        UUID uuid = uuid( bytes );
-        long timestamp = getTimestampInMillis( uuid );
-        int i = 16;
-        if ( tokenCategory.getExpires() ) {
-            long expires = ByteBuffer.wrap( bytes, i, 8 ).getLong();
-            return expires - timestamp;
-        }
-        return Long.MAX_VALUE;
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see
-     * org.apache.usergrid.security.tokens.TokenService#getMaxTokenAgeInSeconds(java.
-     * lang.String)
-     */
-    @Override
-    public long getMaxTokenAgeInSeconds( String token ) {
-        return getMaxTokenAge( token ) / 1000;
-    }
-
-
-    /**
-     * The maximum age a token can be saved for
-     *
-     * @return the maxPersistenceTokenAge
-     */
-    public long getMaxPersistenceTokenAge() {
-        return maxPersistenceTokenAge;
-    }
-
-
-    @Autowired
-    @Qualifier("cassandraService")
-    public void setCassandraService( CassandraService cassandra ) {
-        this.cassandra = cassandra;
-    }
-
-
-    @Autowired
-    public void setEntityManagerFactory( EntityManagerFactory emf ) {
-        this.emf = emf;
-        final Injector injector = ((CpEntityManagerFactory)emf).getApplicationContext().getBean( Injector.class );
-        metricsFactory = injector.getInstance(MetricsFactory.class);
-    }
-
-
-    private String getTokenForUUID( TokenInfo tokenInfo, TokenCategory tokenCategory, UUID uuid ) {
-        int l = 36;
-        if ( tokenCategory.getExpires() ) {
-            l += 8;
-        }
-        ByteBuffer bytes = ByteBuffer.allocate( l );
-        bytes.put( bytes( uuid ) );
-        long expires = Long.MAX_VALUE;
-        if ( tokenCategory.getExpires() ) {
-            expires = ( tokenInfo.getDuration() > 0 ) ?
-                      UUIDUtils.getTimestampInMillis( uuid ) + ( tokenInfo.getDuration() ) :
-                      UUIDUtils.getTimestampInMillis( uuid ) + getExpirationForTokenType( tokenCategory );
-            bytes.putLong( expires );
-        }
-        bytes.put( sha( tokenCategory.getPrefix() + uuid + tokenSecretSalt + expires ) );
-        return tokenCategory.getBase64Prefix() + encodeBase64URLSafeString( bytes.array() );
-    }
-
-
-    /** Calculate the column lifetime and account for long truncation to seconds */
-    private int calcTokenTime( long time ) {
-
-        long secondsDuration = time / 1000;
-
-        int ttl = ( int ) secondsDuration;
-
-        // we've had a ttl that's longer than Integer.MAX value
-        if ( ttl != secondsDuration ) {
-            // Something is up with cassandra... Setting ttl to integer.max
-            // makes the cols disappear.....
-
-            // this should be the line below once this issue is fixed.
-            // https://issues.apache.org/jira/browse/CASSANDRA-4771
-            // ttl = Integer.MAX_VALUE
-
-            // take the max value of an int, and substract the system time off
-            // (in seconds) ,then arbitrarily remove another 120 seconds for good
-            // measure.
-            // Cass calcs the expiration time as
-            // "(System.currentTimeMillis() / 1000) + timeToLive);", so we need
-            // to play nice otherwise it blows up on persist
-            ttl = Integer.MAX_VALUE - ( int ) ( System.currentTimeMillis() / 1000 ) - 120;
-        }
-        // hard cap at the max in o.a.c.db.IColumn
-        if ( ttl > MAX_TTL ) {
-            ttl = MAX_TTL;
-        }
-
-        return ttl;
-    }
-
-
-    private static final int MAX_TTL = 20 * 365 * 24 * 60 * 60;
-
-
-    //-------------------------------------------------------------------------------------------------------
-    //
-    // Central SSO implementation
-
-    public static final String CENTRAL_CONNECTION_POOL_SIZE = "usergrid.central.connection.pool.size";
-    public static final String CENTRAL_CONNECTION_TIMEOUT =   "usergrid.central.connection.timeout";
-    public static final String CENTRAL_READ_TIMEOUT =         "usergrid.central.read.timeout";
-
-
-    // names for metrics to be collected
-    private static final String SSO_TOKENS_REJECTED =         "sso.tokens_rejected";
-    private static final String SSO_TOKENS_VALIDATED =        "sso.tokens_validated";
-    private static final String SSO_CREATED_LOCAL_ADMINS =    "sso.created_local_admins";
-    private static final String SSO_PROCESSING_TIME =         "sso.processing_time";
-
-    //SSO2 implementation
-    public static final String USERGRID_EXTERNAL_SSO_ENABLED = "usergrid.external.sso.enabled";
-    public static final String USERGRID_EXTERNAL_SSO_PROVIDER =    "usergrid.external.sso.provider";
-    public static final String USERGRID_EXTERNAL_SSO_PROVIDER_URL = "usergrid.external.sso.url";
-    public static final String USERGRID_EXTERNAL_SSO_PROVIDER_USER_PROVISION_URL
-        = "usergrid.external.sso.userprovision.url";
-
-
-    private static Client jerseyClient = null;
-
-    @Autowired
-    private ApplicationCreator applicationCreator;
-
-    @Autowired
-    protected ManagementService management;
-
-    @Autowired
-    private SSOProviderFactory ssoProviderFactory;
-
-    MetricsFactory getMetricsFactory() {
-        return metricsFactory;
-    }
-
-
-    public boolean isExternalSSOProviderEnabled() {
-        return Boolean.valueOf(properties.getProperty( USERGRID_EXTERNAL_SSO_ENABLED ));
-    }
-
-    private String getExternalSSOProvider(){
-            return properties.getProperty(USERGRID_EXTERNAL_SSO_PROVIDER);
-    }
-
-    /**
-     * <p>
-     * Validates access token from other or "external" Usergrid system.
-     * Calls other system's /management/me endpoint to get the User
-     * associated with the access token. If user does not exist locally,
-     * then user and organizations will be created. If no user is returned
-     * from the other cluster, then return null.
-     * </p>
-     * <p/>
-     * <p> Part of Usergrid Central SSO feature.
-     * See <a href="https://issues.apache.org/jira/browse/USERGRID-567">USERGRID-567</a>
-     * for details about Usergrid Central SSO.
-     * </p>
-     *
-     * @param extAccessToken Access token from external Usergrid system.
-     * @param ttl            Time to live for token.
-     */
-    public TokenInfo validateExternalToken(String extAccessToken, long ttl, String provider) throws Exception {
-
-
-        ExternalSSOProvider ssoProvider = ssoProviderFactory.getProvider();
-
-        if(provider.equalsIgnoreCase("usergrid")){
-
-            UserInfo userinfo = ssoProvider.validateAndReturnUserInfo(extAccessToken,ttl);
-
-            // Store the external Usergrid access_token as if it were one of our own so we don't have to make the
-            // external HTTP validation call on subsequent requests
-            importToken( extAccessToken, TokenCategory.ACCESS, null, new AuthPrincipalInfo(
-                ADMIN_USER, userinfo.getUuid(), CpNamingUtils.MANAGEMENT_APPLICATION_ID), null, ttl );
-            return getTokenInfo( extAccessToken );
-
-        }else{
-
-            return ssoProvider.validateAndReturnTokenInfo(extAccessToken,ttl);
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
new file mode 100644
index 0000000..d93ecc0
--- /dev/null
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/impl/TokenServiceImpl.java
@@ -0,0 +1,731 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.security.tokens.impl;
+
+
+import com.google.inject.Injector;
+import org.apache.usergrid.corepersistence.CpEntityManagerFactory;
+import org.apache.usergrid.corepersistence.util.CpNamingUtils;
+import org.apache.usergrid.management.ApplicationCreator;
+import org.apache.usergrid.management.ManagementService;
+import org.apache.usergrid.management.UserInfo;
+import org.apache.usergrid.persistence.EntityManagerFactory;
+import org.apache.usergrid.persistence.core.metrics.MetricsFactory;
+import org.apache.usergrid.persistence.entities.Application;
+import org.apache.usergrid.persistence.token.TokenSerialization;
+import org.apache.usergrid.security.AuthPrincipalInfo;
+import org.apache.usergrid.security.AuthPrincipalType;
+import org.apache.usergrid.security.sso.SSOProviderFactory;
+import org.apache.usergrid.security.tokens.TokenCategory;
+import org.apache.usergrid.security.tokens.TokenInfo;
+import org.apache.usergrid.security.tokens.TokenService;
+import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
+import org.apache.usergrid.security.tokens.exceptions.ExpiredTokenException;
+import org.apache.usergrid.security.tokens.exceptions.InvalidTokenException;
+import org.apache.usergrid.security.sso.ExternalSSOProvider;
+import org.apache.usergrid.utils.UUIDUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Assert;
+
+import javax.ws.rs.client.Client;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
+import static org.apache.commons.codec.digest.DigestUtils.sha;
+import static org.apache.usergrid.persistence.token.impl.TokenSerializationImpl.*;
+import static org.apache.usergrid.security.AuthPrincipalType.ADMIN_USER;
+import static org.apache.usergrid.security.tokens.TokenCategory.*;
+import static org.apache.usergrid.utils.ConversionUtils.*;
+import static org.apache.usergrid.utils.MapUtils.hasKeys;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+import static org.apache.usergrid.utils.UUIDUtils.getTimestampInMillis;
+
+
+public class TokenServiceImpl implements TokenService {
+
+    private static final Logger logger = LoggerFactory.getLogger( TokenServiceImpl.class );
+
+    public static final String PROPERTIES_AUTH_TOKEN_SECRET_SALT = "usergrid.auth.token_secret_salt";
+
+    public static final String TOKEN_SECRET_SALT = "super secret token value";
+
+    // Short-lived token is good for 24 hours
+    public static final long SHORT_TOKEN_AGE = 24 * 60 * 60 * 1000;
+
+    // Long-lived token is good for 7 days
+    public static final long LONG_TOKEN_AGE = 7 * 24 * 60 * 60 * 1000;
+
+    String tokenSecretSalt = TOKEN_SECRET_SALT;
+
+    long maxPersistenceTokenAge = LONG_TOKEN_AGE;
+
+    Map<TokenCategory, Long> tokenExpirations =
+            hashMap( ACCESS, LONG_TOKEN_AGE ).map( REFRESH, LONG_TOKEN_AGE ).map( EMAIL, LONG_TOKEN_AGE )
+                    .map( OFFLINE, LONG_TOKEN_AGE );
+
+    long maxAccessTokenAge = SHORT_TOKEN_AGE;
+    long maxRefreshTokenAge = LONG_TOKEN_AGE;
+    long maxEmailTokenAge = LONG_TOKEN_AGE;
+    long maxOfflineTokenAge = LONG_TOKEN_AGE;
+
+    protected Properties properties;
+
+    protected EntityManagerFactory emf;
+
+    private MetricsFactory metricsFactory;
+
+    private TokenSerialization tokenSerialization;
+
+
+    public TokenServiceImpl() {
+    }
+
+
+    private long getExpirationProperty( String name, long default_expiration ) {
+        long expires = Long.parseLong(
+                properties.getProperty( "usergrid.auth.token." + name + ".expires", "" + default_expiration ) );
+        return expires > 0 ? expires : default_expiration;
+    }
+
+
+    private long getExpirationForTokenType( TokenCategory tokenCategory ) {
+        Long l = tokenExpirations.get( tokenCategory );
+        if ( l != null ) {
+            return l;
+        }
+        return SHORT_TOKEN_AGE;
+    }
+
+
+    private void setExpirationFromProperties( String name ) {
+        TokenCategory tokenCategory = TokenCategory.valueOf( name.toUpperCase() );
+        long expires = Long.parseLong( properties.getProperty( "usergrid.auth.token." + name + ".expires",
+                "" + getExpirationForTokenType( tokenCategory ) ) );
+        if ( expires > 0 ) {
+            tokenExpirations.put( tokenCategory, expires );
+        }
+        logger.info( "{} token expires after {} seconds", name, getExpirationForTokenType( tokenCategory ) / 1000 );
+    }
+
+
+    @Autowired
+    public void setProperties( Properties properties ) {
+        this.properties = properties;
+
+        if ( properties != null ) {
+            maxPersistenceTokenAge = getExpirationProperty( "persistence", maxPersistenceTokenAge );
+
+            setExpirationFromProperties( "access" );
+            setExpirationFromProperties( "refresh" );
+            setExpirationFromProperties( "email" );
+            setExpirationFromProperties( "offline" );
+
+            tokenSecretSalt = properties.getProperty( PROPERTIES_AUTH_TOKEN_SECRET_SALT, TOKEN_SECRET_SALT );
+        }
+    }
+
+
+    @Override
+    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
+                               Map<String, Object> state, long duration ) throws Exception {
+        return createToken( tokenCategory, type, principal, state, duration, null, System.currentTimeMillis() );
+    }
+
+
+    @Override
+    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
+                               Map<String, Object> state, long duration, UUID workflowOrgId ) throws Exception {
+        return createToken( tokenCategory, type, principal, state, duration, workflowOrgId, System.currentTimeMillis() );
+    }
+
+
+    /** Exposed for testing purposes. The interface does not allow creation timestamp checking */
+    public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
+                               Map<String, Object> state, long duration, UUID workflowOrgId,
+                               long creationTimestamp ) throws Exception {
+
+        long maxTokenTtl = getMaxTtl( tokenCategory, principal );
+
+        if ( duration > maxTokenTtl ) {
+            throw new IllegalArgumentException(
+                    String.format( "Your token age cannot be more than the maximum age of %d milliseconds",
+                            maxTokenTtl ) );
+        }
+
+        if ( duration == 0 ) {
+            duration = maxTokenTtl;
+        }
+
+        if ( principal != null ) {
+            Assert.notNull( principal.getType() );
+            Assert.notNull( principal.getApplicationId() );
+            Assert.notNull( principal.getUuid() );
+        }
+
+        // create UUID that we will use to store token info in our database
+        UUID uuid = UUIDUtils.newTimeUUID( creationTimestamp );
+
+        long timestamp = getTimestampInMillis( uuid );
+        if ( type == null ) {
+            type = TOKEN_TYPE_ACCESS;
+        }
+        TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration, principal,
+                state, workflowOrgId );
+        putTokenInfo( tokenInfo );
+
+        // generate token from the UUID that we created
+        return getTokenForUUID(tokenInfo, tokenCategory, uuid);
+    }
+
+
+    @Override
+    public void importToken(String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
+                            Map<String, Object> state, long duration) throws Exception {
+
+        importToken(token, tokenCategory, type, principal, state, duration, null);
+    }
+
+
+    @Override
+    public void importToken(String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo principal,
+                            Map<String, Object> state, long duration, UUID workflowOrgId) throws Exception {
+
+        // same logic as create token
+
+        long maxTokenTtl = getMaxTtl( tokenCategory, principal );
+
+        if ( duration > maxTokenTtl ) {
+            throw new IllegalArgumentException(
+                    String.format( "Your token age cannot be more than the maximum age of %d milliseconds",
+                            maxTokenTtl ) );
+        }
+
+        if ( duration == 0 ) {
+            duration = maxTokenTtl;
+        }
+
+        if ( principal != null ) {
+            Assert.notNull( principal.getType() );
+            Assert.notNull( principal.getApplicationId() );
+            Assert.notNull( principal.getUuid() );
+        }
+
+        // except that we generate the UUID based on the token
+
+        UUID uuid = getUUIDForToken(token);
+
+        long timestamp = getTimestampInMillis( uuid );
+        if ( type == null ) {
+            type = TOKEN_TYPE_ACCESS;
+        }
+
+        TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration, principal,
+                state, workflowOrgId );
+        putTokenInfo( tokenInfo );
+    }
+
+
+    @Override
+    public TokenInfo getTokenInfo( String token ) throws Exception {
+        return getTokenInfo(token, true);
+    }
+
+
+    @Override
+    public TokenInfo getTokenInfo( String token, boolean updateAccessTime ) throws Exception {
+
+        UUID uuid;
+
+
+        /** Pre-validation of the token string based on Usergrid's encoding scheme.
+         *
+         * If the token does not parse out a UUID, then it's not a Usergrid token.  Check if External SSO provider
+         * is configured, which is not Usergrid and immediately try to validate the token based on this parsing
+         * information.
+         */
+        try{
+            uuid = getUUIDForToken( token );
+        }
+        catch (ExpiredTokenException expiredTokenException){
+            throw new ExpiredTokenException(expiredTokenException.getMessage());
+        }
+        catch(Exception e){
+
+            // If the token doesn't parse as a Usergrid token, see if an external provider other than Usergrid is
+            // enabled.  If so, just validate the external token.
+            try{
+                if( isExternalSSOProviderEnabled() && !getExternalSSOProvider().equalsIgnoreCase("usergrid")) {
+                    return validateExternalToken(token, 1, getExternalSSOProvider());
+                }else{
+                    throw new IllegalArgumentException("invalid external provider : " + getExternalSSOProvider()); // re-throw the error
+                }
+            }
+            catch (NullPointerException npe){
+                throw new IllegalArgumentException("The SSO provider in the config is empty.");
+            }
+
+        }
+
+        final TokenInfo tokenInfo;
+
+        /**
+         * Now try actual Usergrid token validations.  First try locally.  If that fails and SSO is enabled with
+         * Usergrid being a provider, validate the external token.
+         */
+        try {
+            tokenInfo = getTokenInfo( uuid );
+        } catch (InvalidTokenException e){
+            // Try the request from Usergrid, conditions are specific so we don't incur perf hits for unncessary
+            // token validations that are known to not
+            if ( isExternalSSOProviderEnabled() && getExternalSSOProvider().equalsIgnoreCase("usergrid") ){
+                return validateExternalToken( token, maxPersistenceTokenAge, getExternalSSOProvider() );
+            }else{
+                throw e; // re-throw the error
+            }
+        }
+
+        if (updateAccessTime) {
+            //update the token
+            long now = currentTimeMillis();
+
+            long maxTokenTtl = getMaxTtl(TokenCategory.getFromBase64String(token), tokenInfo.getPrincipal());
+
+            long inactive = now - tokenInfo.getAccessed();
+            // Long.MIN_VALUE indicates that nothing needs to be updated for token inactive property
+            if (inactive < tokenInfo.getInactive()) {
+               inactive = Long.MIN_VALUE;
+            }
+
+            tokenSerialization.updateTokenAccessTime(uuid, now, inactive, calcTokenTime(tokenInfo.getExpiration(maxTokenTtl)));
+        }
+
+        return tokenInfo;
+    }
+
+
+    /** Get the max ttl per app. This is null safe,and will return the default in the case of missing data */
+    private long getMaxTtl( TokenCategory tokenCategory, AuthPrincipalInfo principal ) throws Exception {
+
+        if ( principal == null ) {
+            return maxPersistenceTokenAge;
+        }
+        long defaultMaxTtlForTokenType = getExpirationForTokenType( tokenCategory );
+
+        Application application = emf.getEntityManager( principal.getApplicationId() )
+                                     .get( principal.getApplicationId(), Application.class );
+
+        if ( application == null ) {
+            return defaultMaxTtlForTokenType;
+        }
+
+        // set the max to the default
+        long maxTokenTtl = defaultMaxTtlForTokenType;
+
+        // it's been defined on the expiration, override it
+        if ( application.getAccesstokenttl() != null ) {
+            maxTokenTtl = application.getAccesstokenttl();
+
+            // it's set to 0 which equals infinity, set our expiration to
+            // LONG.MAX
+            if ( maxTokenTtl == 0 ) {
+                maxTokenTtl = Long.MAX_VALUE;
+            }
+        }
+
+        return maxTokenTtl;
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * org.apache.usergrid.security.tokens.TokenService#removeTokens(org.apache.usergrid.security
+     * .AuthPrincipalInfo)
+     */
+    @Override
+    public void removeTokens( AuthPrincipalInfo principal ) throws Exception {
+
+        final List<UUID> tokenIds = getTokenUUIDS( principal );
+        tokenSerialization.deleteTokens(tokenIds, principalKey( principal ));
+
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * org.apache.usergrid.security.tokens.TokenService#revokeToken(java.lang.String)
+     */
+    @Override
+    public void revokeToken( String token ) {
+
+        TokenInfo info;
+
+        try {
+            info = getTokenInfo( token );
+        }
+        catch ( Exception e ) {
+            logger.error( "Unable to find token with the specified value ignoring request.  Value : {}", token );
+            return;
+        }
+
+        final UUID tokenId = info.getUuid();
+
+        // clean up the link in the principal -> token index if the principal is
+        // on the token
+        if ( info.getPrincipal() != null ) {
+            tokenSerialization.revokeToken(tokenId, principalKey( info.getPrincipal()));
+        }else{
+            tokenSerialization.revokeToken(tokenId, null);
+        }
+
+    }
+
+
+    private TokenInfo getTokenInfo( UUID uuid ) throws Exception {
+        if ( uuid == null ) {
+            throw new InvalidTokenException( "No token specified" );
+        }
+
+        Map<String, Object> tokenDetails = tokenSerialization.getTokenInfo(uuid);
+
+        if ( !hasKeys( tokenDetails, REQUIRED_TOKEN_PROPERTIES ) ) {
+            throw new InvalidTokenException( "Token not found in database" );
+        }
+
+        String type = (String) tokenDetails.get(TOKEN_TYPE);
+        long created = (long) tokenDetails.get(TOKEN_CREATED);
+        long accessed = (long) tokenDetails.get(TOKEN_ACCESSED);
+        long inactive = (long) tokenDetails.get(TOKEN_INACTIVE);
+        long duration = (long) tokenDetails.get(TOKEN_DURATION);
+
+        String principalTypeStr = (String) tokenDetails.get(TOKEN_PRINCIPAL_TYPE);
+
+        AuthPrincipalType principalType = null;
+        if ( principalTypeStr != null ) {
+            try {
+                principalType = AuthPrincipalType.valueOf( principalTypeStr.toUpperCase() );
+            }
+            catch ( IllegalArgumentException e ) {
+                logger.warn("Unable to convert authPrincipal Type from string to enum");
+            }
+        }
+        AuthPrincipalInfo principal = null;
+        if ( principalType != null ) {
+            UUID entityId = (UUID) tokenDetails.get(TOKEN_ENTITY);
+            UUID appId = (UUID) tokenDetails.get(TOKEN_APPLICATION);
+            principal = new AuthPrincipalInfo( principalType, entityId, appId );
+        }
+
+        @SuppressWarnings("unchecked")
+        Map<String, Object> state = ( Map<String, Object> ) tokenDetails.get( TOKEN_STATE );
+
+        UUID workflowOrgId = null;
+        if (tokenDetails.containsKey(TOKEN_WORKFLOW_ORG_ID)) {
+            workflowOrgId = (UUID) tokenDetails.get(TOKEN_WORKFLOW_ORG_ID);
+        }
+
+        return new TokenInfo( uuid, type, created, accessed, inactive, duration, principal, state, workflowOrgId );
+    }
+
+
+    private void putTokenInfo( TokenInfo tokenInfo ) throws Exception {
+
+        int ttl = calcTokenTime( tokenInfo.getDuration() );
+        final Map<String, Object> tokenDetails = new HashMap<>();
+
+        tokenDetails.put(TOKEN_UUID, tokenInfo.getUuid());
+        tokenDetails.put(TOKEN_TYPE, tokenInfo.getType());
+        tokenDetails.put(TOKEN_CREATED, tokenInfo.getCreated());
+        tokenDetails.put(TOKEN_ACCESSED, tokenInfo.getAccessed());
+        tokenDetails.put(TOKEN_INACTIVE, tokenInfo.getInactive());
+        tokenDetails.put(TOKEN_DURATION, tokenInfo.getDuration());
+
+        ByteBuffer principalKeyBuffer = null;
+        if ( tokenInfo.getPrincipal() != null ) {
+
+            AuthPrincipalInfo principalInfo = tokenInfo.getPrincipal();
+
+            tokenDetails.put(TOKEN_PRINCIPAL_TYPE, principalInfo.getType().toString().toLowerCase());
+            tokenDetails.put(TOKEN_ENTITY, principalInfo.getUuid());
+            tokenDetails.put(TOKEN_APPLICATION, principalInfo.getApplicationId());
+
+          /*
+           * write to the PRINCIPAL+TOKEN The format is as follow
+           *
+           * appid+principalId+principalType :{ tokenuuid: 0x00}
+           */
+            principalKeyBuffer = principalKey( principalInfo );
+
+        }
+
+        if ( tokenInfo.getState() != null ) {
+            tokenDetails.put(TOKEN_STATE, tokenInfo.getState());
+        }
+
+        if ( tokenInfo.getWorkflowOrgId() != null ) {
+            tokenDetails.put(TOKEN_WORKFLOW_ORG_ID, tokenInfo.getWorkflowOrgId());
+        }
+
+        tokenSerialization.putTokenInfo(tokenInfo.getUuid(), tokenDetails, principalKeyBuffer, ttl);
+    }
+
+
+    /** Load all the token uuids for a principal info */
+    private List<UUID> getTokenUUIDS( AuthPrincipalInfo principal ) throws Exception {
+
+        return tokenSerialization.getTokensForPrincipal(principalKey( principal ));
+    }
+
+
+    private ByteBuffer principalKey( AuthPrincipalInfo principalInfo ) {
+        // 66 bytes, 2 UUIDS + 2 chars for prefix
+        ByteBuffer buff = ByteBuffer.allocate( 32 * 2 + 2 );
+        buff.put( bytes( principalInfo.getApplicationId() ) );
+        buff.put( bytes( principalInfo.getUuid() ) );
+        buff.put( bytes( principalInfo.getType().getPrefix() ) );
+        buff.rewind();
+
+        return buff;
+    }
+
+
+    private UUID getUUIDForToken(String token ) throws ExpiredTokenException, BadTokenException {
+        TokenCategory tokenCategory = TokenCategory.getFromBase64String( token );
+        byte[] bytes = decodeBase64( token.substring( TokenCategory.BASE64_PREFIX_LENGTH ) );
+        UUID uuid = uuid( bytes );
+        int i = 16;
+        long expires = Long.MAX_VALUE;
+        if ( tokenCategory.getExpires() ) {
+            expires = ByteBuffer.wrap( bytes, i, 8 ).getLong();
+            i = 24;
+        }
+        ByteBuffer expected = ByteBuffer.allocate( 20 );
+        expected.put( sha( tokenCategory.getPrefix() + uuid + tokenSecretSalt + expires ) );
+        expected.rewind();
+        ByteBuffer signature = ByteBuffer.wrap( bytes, i, 20 );
+
+
+        if ( !signature.equals( expected ) ) {
+            throw new BadTokenException( "Invalid token signature" );
+        }
+
+
+        long expirationDelta = System.currentTimeMillis() - expires;
+
+        if ( expires != Long.MAX_VALUE && expirationDelta > 0 ) {
+            throw new ExpiredTokenException( String.format( "Token expired %d milliseconds ago.", expirationDelta ) );
+        }
+        return uuid;
+    }
+
+
+    @Override
+    public long getMaxTokenAge( String token ) {
+        TokenCategory tokenCategory = TokenCategory.getFromBase64String( token );
+        byte[] bytes = decodeBase64( token.substring( TokenCategory.BASE64_PREFIX_LENGTH ) );
+        UUID uuid = uuid( bytes );
+        long timestamp = getTimestampInMillis( uuid );
+        int i = 16;
+        if ( tokenCategory.getExpires() ) {
+            long expires = ByteBuffer.wrap( bytes, i, 8 ).getLong();
+            return expires - timestamp;
+        }
+        return Long.MAX_VALUE;
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * org.apache.usergrid.security.tokens.TokenService#getMaxTokenAgeInSeconds(java.
+     * lang.String)
+     */
+    @Override
+    public long getMaxTokenAgeInSeconds( String token ) {
+        return getMaxTokenAge( token ) / 1000;
+    }
+
+
+    /**
+     * The maximum age a token can be saved for
+     *
+     * @return the maxPersistenceTokenAge
+     */
+    public long getMaxPersistenceTokenAge() {
+        return maxPersistenceTokenAge;
+    }
+
+    @Autowired
+    public void setEntityManagerFactory( EntityManagerFactory emf ) {
+        this.emf = emf;
+        final Injector injector = ((CpEntityManagerFactory)emf).getApplicationContext().getBean( Injector.class );
+        this.metricsFactory = injector.getInstance(MetricsFactory.class);
+        this.tokenSerialization = injector.getInstance(TokenSerialization.class);
+    }
+
+
+    private String getTokenForUUID( TokenInfo tokenInfo, TokenCategory tokenCategory, UUID uuid ) {
+        int l = 36;
+        if ( tokenCategory.getExpires() ) {
+            l += 8;
+        }
+        ByteBuffer bytes = ByteBuffer.allocate( l );
+        bytes.put( bytes( uuid ) );
+        long expires = Long.MAX_VALUE;
+        if ( tokenCategory.getExpires() ) {
+            expires = ( tokenInfo.getDuration() > 0 ) ?
+                      UUIDUtils.getTimestampInMillis( uuid ) + ( tokenInfo.getDuration() ) :
+                      UUIDUtils.getTimestampInMillis( uuid ) + getExpirationForTokenType( tokenCategory );
+            bytes.putLong( expires );
+        }
+        bytes.put( sha( tokenCategory.getPrefix() + uuid + tokenSecretSalt + expires ) );
+        return tokenCategory.getBase64Prefix() + encodeBase64URLSafeString( bytes.array() );
+    }
+
+
+    /** Calculate the column lifetime and account for long truncation to seconds */
+    private int calcTokenTime( long time ) {
+
+        long secondsDuration = time / 1000;
+
+        int ttl = ( int ) secondsDuration;
+
+        // we've had a ttl that's longer than Integer.MAX value
+        if ( ttl != secondsDuration ) {
+            // Something is up with cassandra... Setting ttl to integer.max
+            // makes the cols disappear.....
+
+            // this should be the line below once this issue is fixed.
+            // https://issues.apache.org/jira/browse/CASSANDRA-4771
+            // ttl = Integer.MAX_VALUE
+
+            // take the max value of an int, and substract the system time off
+            // (in seconds) ,then arbitrarily remove another 120 seconds for good
+            // measure.
+            // Cass calcs the expiration time as
+            // "(System.currentTimeMillis() / 1000) + timeToLive);", so we need
+            // to play nice otherwise it blows up on persist
+            ttl = Integer.MAX_VALUE - ( int ) ( System.currentTimeMillis() / 1000 ) - 120;
+        }
+        // hard cap at the max in o.a.c.db.IColumn
+        if ( ttl > MAX_TTL ) {
+            ttl = MAX_TTL;
+        }
+
+        return ttl;
+    }
+
+
+    private static final int MAX_TTL = 20 * 365 * 24 * 60 * 60;
+
+
+    //-------------------------------------------------------------------------------------------------------
+    //
+    // Central SSO implementation
+
+    public static final String CENTRAL_CONNECTION_POOL_SIZE = "usergrid.central.connection.pool.size";
+    public static final String CENTRAL_CONNECTION_TIMEOUT =   "usergrid.central.connection.timeout";
+    public static final String CENTRAL_READ_TIMEOUT =         "usergrid.central.read.timeout";
+
+
+    // names for metrics to be collected
+    private static final String SSO_TOKENS_REJECTED =         "sso.tokens_rejected";
+    private static final String SSO_TOKENS_VALIDATED =        "sso.tokens_validated";
+    private static final String SSO_CREATED_LOCAL_ADMINS =    "sso.created_local_admins";
+    private static final String SSO_PROCESSING_TIME =         "sso.processing_time";
+
+    //SSO2 implementation
+    public static final String USERGRID_EXTERNAL_SSO_ENABLED = "usergrid.external.sso.enabled";
+    public static final String USERGRID_EXTERNAL_SSO_PROVIDER =    "usergrid.external.sso.provider";
+    public static final String USERGRID_EXTERNAL_SSO_PROVIDER_URL = "usergrid.external.sso.url";
+    public static final String USERGRID_EXTERNAL_SSO_PROVIDER_USER_PROVISION_URL
+        = "usergrid.external.sso.userprovision.url";
+
+
+    private static Client jerseyClient = null;
+
+    @Autowired
+    private ApplicationCreator applicationCreator;
+
+    @Autowired
+    protected ManagementService management;
+
+    @Autowired
+    private SSOProviderFactory ssoProviderFactory;
+
+    MetricsFactory getMetricsFactory() {
+        return metricsFactory;
+    }
+
+
+    public boolean isExternalSSOProviderEnabled() {
+        return Boolean.valueOf(properties.getProperty( USERGRID_EXTERNAL_SSO_ENABLED ));
+    }
+
+    private String getExternalSSOProvider(){
+            return properties.getProperty(USERGRID_EXTERNAL_SSO_PROVIDER);
+    }
+
+    /**
+     * <p>
+     * Validates access token from other or "external" Usergrid system.
+     * Calls other system's /management/me endpoint to get the User
+     * associated with the access token. If user does not exist locally,
+     * then user and organizations will be created. If no user is returned
+     * from the other cluster, then return null.
+     * </p>
+     * <p/>
+     * <p> Part of Usergrid Central SSO feature.
+     * See <a href="https://issues.apache.org/jira/browse/USERGRID-567">USERGRID-567</a>
+     * for details about Usergrid Central SSO.
+     * </p>
+     *
+     * @param extAccessToken Access token from external Usergrid system.
+     * @param ttl            Time to live for token.
+     */
+    public TokenInfo validateExternalToken(String extAccessToken, long ttl, String provider) throws Exception {
+
+
+        ExternalSSOProvider ssoProvider = ssoProviderFactory.getProvider();
+
+        if(provider.equalsIgnoreCase("usergrid")){
+
+            UserInfo userinfo = ssoProvider.validateAndReturnUserInfo(extAccessToken,ttl);
+
+            // Store the external Usergrid access_token as if it were one of our own so we don't have to make the
+            // external HTTP validation call on subsequent requests
+            importToken( extAccessToken, TokenCategory.ACCESS, null, new AuthPrincipalInfo(
+                ADMIN_USER, userinfo.getUuid(), CpNamingUtils.MANAGEMENT_APPLICATION_ID), null, ttl );
+            return getTokenInfo( extAccessToken );
+
+        }else{
+
+            return ssoProvider.validateAndReturnTokenInfo(extAccessToken,ttl);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/services/src/main/resources/usergrid-services-context.xml
----------------------------------------------------------------------
diff --git a/stack/services/src/main/resources/usergrid-services-context.xml b/stack/services/src/main/resources/usergrid-services-context.xml
index 268b5ec..45f4c48 100644
--- a/stack/services/src/main/resources/usergrid-services-context.xml
+++ b/stack/services/src/main/resources/usergrid-services-context.xml
@@ -63,8 +63,7 @@
 
     <bean id="taskExecutor" class="org.springframework.core.task.SyncTaskExecutor"/>
 
-    <bean id="tokenService" class="org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl">
-        <property name="cassandraService" ref="cassandraService"/>
+    <bean id="tokenService" class="org.apache.usergrid.security.tokens.impl.TokenServiceImpl">
         <property name="entityManagerFactory" ref="entityManagerFactory"/>
     </bean>
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java b/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
index c4cc10c..452ee61 100644
--- a/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
+++ b/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
@@ -38,7 +38,7 @@ import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.persistence.entities.Application;
 import org.apache.usergrid.security.AuthPrincipalInfo;
 import org.apache.usergrid.security.AuthPrincipalType;
-import org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl;
+import org.apache.usergrid.security.tokens.impl.TokenServiceImpl;
 import org.apache.usergrid.security.tokens.exceptions.ExpiredTokenException;
 import org.apache.usergrid.security.tokens.exceptions.InvalidTokenException;
 import org.apache.usergrid.utils.UUIDUtils;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/146e47d6/stack/websocket/src/test/resources/testApplicationContext.xml
----------------------------------------------------------------------
diff --git a/stack/websocket/src/test/resources/testApplicationContext.xml b/stack/websocket/src/test/resources/testApplicationContext.xml
index d92f4fb..bbf7b93 100644
--- a/stack/websocket/src/test/resources/testApplicationContext.xml
+++ b/stack/websocket/src/test/resources/testApplicationContext.xml
@@ -130,7 +130,7 @@
 		</constructor-arg>
 	</bean>
 
-	<bean id="tokenService" class="org.apache.usergrid.security.tokens.cassandra.TokenServiceImpl"/>
+	<bean id="tokenService" class="org.apache.usergrid.security.tokens.impl.TokenServiceImpl"/>
 
 	<bean id="managementService" class="org.apache.usergrid.management.cassandra.ManagementServiceImpl" />