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" />