Browse code

[core] FEATBL-885 Feat: Add API to make a service session last longer (7 days) instead of 20 minutes. Use it for mapi sessions

Thomas Cataldo authored on 03/10/2019 14:06:23
Showing 38 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,44 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2019
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.api;
20
+
21
+import javax.ws.rs.DELETE;
22
+import javax.ws.rs.POST;
23
+import javax.ws.rs.PUT;
24
+import javax.ws.rs.Path;
25
+
26
+import net.bluemind.core.api.BMApi;
27
+
28
+@BMApi(version = "3", internal = true)
29
+@Path("/auth/token/{sid}")
30
+public interface ISecurityToken {
31
+
32
+	@PUT
33
+	@Path("_upgrade")
34
+	void upgrade();
35
+
36
+	@POST
37
+	@Path("_renew")
38
+	void renew();
39
+
40
+	@DELETE
41
+	@Path("_delete")
42
+	void destroy();
43
+
44
+}
... ...
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
22 22
 import static org.junit.Assert.assertNotNull;
23 23
 import static org.junit.Assert.assertNull;
24 24
 import static org.junit.Assert.assertTrue;
25
+import static org.junit.Assert.fail;
25 26
 
26 27
 import java.util.ArrayList;
27 28
 import java.util.Arrays;
... ...
@@ -40,10 +41,12 @@ import net.bluemind.authentication.api.APIKey;
40 41
 import net.bluemind.authentication.api.AuthUser;
41 42
 import net.bluemind.authentication.api.IAPIKeys;
42 43
 import net.bluemind.authentication.api.IAuthentication;
44
+import net.bluemind.authentication.api.ISecurityToken;
43 45
 import net.bluemind.authentication.api.LoginResponse;
44 46
 import net.bluemind.authentication.api.LoginResponse.Status;
45 47
 import net.bluemind.config.Token;
46 48
 import net.bluemind.core.api.Email;
49
+import net.bluemind.core.api.fault.ErrorCode;
47 50
 import net.bluemind.core.api.fault.ServerFault;
48 51
 import net.bluemind.core.container.model.ItemValue;
49 52
 import net.bluemind.core.context.SecurityContext;
... ...
@@ -83,11 +86,6 @@ public class AuthenticationTests {
83 86
 		esServer.ip = new BmConfIni().get("es-host");
84 87
 		esServer.tags = Lists.newArrayList("bm/es");
85 88
 
86
-		String cyrusIp = new BmConfIni().get("imap-role");
87
-		Server imapServer = new Server();
88
-		imapServer.ip = cyrusIp;
89
-		imapServer.tags = Lists.newArrayList("mail/imap");
90
-
91 89
 		PopulateHelper.initGlobalVirt(esServer);
92 90
 
93 91
 		PopulateHelper.addDomainAdmin("admin0", "global.virt", Routing.external);
... ...
@@ -188,6 +186,11 @@ public class AuthenticationTests {
188 186
 				.instance(IAuthentication.class);
189 187
 	}
190 188
 
189
+	private ISecurityToken getTokenService(String sessionId) throws ServerFault {
190
+		return ClientSideServiceProvider.getProvider("http://127.0.0.1:8090", sessionId).instance(ISecurityToken.class,
191
+				sessionId);
192
+	}
193
+
191 194
 	@Test
192 195
 	public void testLogout() throws Exception {
193 196
 		initState();
... ...
@@ -339,4 +342,36 @@ public class AuthenticationTests {
339 342
 		assertEquals(response.authUser.uid, "user2");
340 343
 	}
341 344
 
345
+	@Test
346
+	public void testPromoteToToken() throws Exception {
347
+		initState();
348
+		IAuthentication authentication = getService(null);
349
+		LoginResponse response = authentication.login("admin0@global.virt", "admin", "junit");
350
+		assertEquals(Status.Ok, response.status);
351
+
352
+		ISecurityToken secToken = getTokenService(response.authKey);
353
+		secToken.upgrade();
354
+		String permToken = response.authKey;
355
+
356
+		// destroy the volatile auth key
357
+		authentication = getService(response.authKey);
358
+		authentication.logout();
359
+
360
+		// verify the token is re-activated after logout
361
+		authentication = getService(permToken);
362
+		AuthUser current = authentication.getCurrentUser();
363
+		assertNotNull(current);
364
+		assertEquals("admin0", current.uid);
365
+		secToken.renew();
366
+
367
+		System.err.println("destroying...");
368
+		secToken.destroy();
369
+		try {
370
+			authentication.ping();
371
+			fail("ping should fail after token is destroyed");
372
+		} catch (ServerFault sf) {
373
+			assertEquals(ErrorCode.AUTHENTICATION_FAIL, sf.getCode());
374
+		}
375
+	}
376
+
342 377
 }
... ...
@@ -3,5 +3,6 @@
3 3
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
4 4
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
5 5
 	<classpathentry kind="src" path="src/"/>
6
+	<classpathentry kind="src" path="hollow-generated"/>
6 7
 	<classpathentry kind="output" path="target/classes"/>
7 8
 </classpath>
... ...
@@ -28,6 +28,7 @@ Require-Bundle: net.bluemind.authentication.api;bundle-version="1.0.0";visibilit
28 28
  net.bluemind.role.api,
29 29
  net.bluemind.core.container.service,
30 30
  net.bluemind.system.api,
31
- net.bluemind.user.hook
31
+ net.bluemind.user.hook,
32
+ com.netflix.hollow
32 33
 Export-Package: net.bluemind.authentication.service
33 34
 
... ...
@@ -1,4 +1,5 @@
1
-source.. = src/
1
+source.. = src/,\
2
+           hollow-generated/
2 3
 bin.includes = META-INF/,\
3 4
                .,\
4 5
                plugin.xml
5 6
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.HollowObject;
4
+import com.netflix.hollow.core.schema.HollowObjectSchema;
5
+
6
+import com.netflix.hollow.tools.stringifier.HollowRecordStringifier;
7
+
8
+@SuppressWarnings("all")
9
+public class HString extends HollowObject {
10
+
11
+    public HString(StringDelegate delegate, int ordinal) {
12
+        super(delegate, ordinal);
13
+    }
14
+
15
+    public String getValue() {
16
+        return delegate().getValue(ordinal);
17
+    }
18
+
19
+    public boolean isValueEqual(String testValue) {
20
+        return delegate().isValueEqual(ordinal, testValue);
21
+    }
22
+
23
+    public TokensAPI api() {
24
+        return typeApi().getAPI();
25
+    }
26
+
27
+    public StringTypeAPI typeApi() {
28
+        return delegate().getTypeAPI();
29
+    }
30
+
31
+    protected StringDelegate delegate() {
32
+        return (StringDelegate)delegate;
33
+    }
34
+
35
+}
0 36
\ No newline at end of file
1 37
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.consumer.HollowConsumer;
4
+import com.netflix.hollow.api.consumer.data.AbstractHollowDataAccessor;
5
+import com.netflix.hollow.core.index.key.PrimaryKey;
6
+import com.netflix.hollow.core.read.engine.HollowReadStateEngine;
7
+
8
+@SuppressWarnings("all")
9
+public class StringDataAccessor extends AbstractHollowDataAccessor<HString> {
10
+
11
+    public static final String TYPE = "HString";
12
+    private TokensAPI api;
13
+
14
+    public StringDataAccessor(HollowConsumer consumer) {
15
+        super(consumer, TYPE);
16
+        this.api = (TokensAPI)consumer.getAPI();
17
+    }
18
+
19
+    public StringDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api) {
20
+        super(rStateEngine, TYPE);
21
+        this.api = api;
22
+    }
23
+
24
+    public StringDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api, String ... fieldPaths) {
25
+        super(rStateEngine, TYPE, fieldPaths);
26
+        this.api = api;
27
+    }
28
+
29
+    public StringDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api, PrimaryKey primaryKey) {
30
+        super(rStateEngine, TYPE, primaryKey);
31
+        this.api = api;
32
+    }
33
+
34
+    @Override public HString getRecord(int ordinal){
35
+        return api.getHString(ordinal);
36
+    }
37
+
38
+}
0 39
\ No newline at end of file
1 40
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectDelegate;
4
+
5
+
6
+@SuppressWarnings("all")
7
+public interface StringDelegate extends HollowObjectDelegate {
8
+
9
+    public String getValue(int ordinal);
10
+
11
+    public boolean isValueEqual(int ordinal, String testValue);
12
+
13
+    public StringTypeAPI getTypeAPI();
14
+
15
+}
0 16
\ No newline at end of file
1 17
new file mode 100644
... ...
@@ -0,0 +1,48 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectAbstractDelegate;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+import com.netflix.hollow.core.schema.HollowObjectSchema;
6
+import com.netflix.hollow.api.custom.HollowTypeAPI;
7
+import com.netflix.hollow.api.objects.delegate.HollowCachedDelegate;
8
+
9
+@SuppressWarnings("all")
10
+public class StringDelegateCachedImpl extends HollowObjectAbstractDelegate implements HollowCachedDelegate, StringDelegate {
11
+
12
+    private final String value;
13
+    private StringTypeAPI typeAPI;
14
+
15
+    public StringDelegateCachedImpl(StringTypeAPI typeAPI, int ordinal) {
16
+        this.value = typeAPI.getValue(ordinal);
17
+        this.typeAPI = typeAPI;
18
+    }
19
+
20
+    public String getValue(int ordinal) {
21
+        return value;
22
+    }
23
+
24
+    public boolean isValueEqual(int ordinal, String testValue) {
25
+        if(testValue == null)
26
+            return value == null;
27
+        return testValue.equals(value);
28
+    }
29
+
30
+    @Override
31
+    public HollowObjectSchema getSchema() {
32
+        return typeAPI.getTypeDataAccess().getSchema();
33
+    }
34
+
35
+    @Override
36
+    public HollowObjectTypeDataAccess getTypeDataAccess() {
37
+        return typeAPI.getTypeDataAccess();
38
+    }
39
+
40
+    public StringTypeAPI getTypeAPI() {
41
+        return typeAPI;
42
+    }
43
+
44
+    public void updateTypeAPI(HollowTypeAPI typeAPI) {
45
+        this.typeAPI = (StringTypeAPI) typeAPI;
46
+    }
47
+
48
+}
0 49
\ No newline at end of file
1 50
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectAbstractDelegate;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+import com.netflix.hollow.core.schema.HollowObjectSchema;
6
+
7
+@SuppressWarnings("all")
8
+public class StringDelegateLookupImpl extends HollowObjectAbstractDelegate implements StringDelegate {
9
+
10
+    private final StringTypeAPI typeAPI;
11
+
12
+    public StringDelegateLookupImpl(StringTypeAPI typeAPI) {
13
+        this.typeAPI = typeAPI;
14
+    }
15
+
16
+    public String getValue(int ordinal) {
17
+        return typeAPI.getValue(ordinal);
18
+    }
19
+
20
+    public boolean isValueEqual(int ordinal, String testValue) {
21
+        return typeAPI.isValueEqual(ordinal, testValue);
22
+    }
23
+
24
+    public StringTypeAPI getTypeAPI() {
25
+        return typeAPI;
26
+    }
27
+
28
+    @Override
29
+    public HollowObjectSchema getSchema() {
30
+        return typeAPI.getTypeDataAccess().getSchema();
31
+    }
32
+
33
+    @Override
34
+    public HollowObjectTypeDataAccess getTypeDataAccess() {
35
+        return typeAPI.getTypeDataAccess();
36
+    }
37
+
38
+}
0 39
\ No newline at end of file
1 40
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.provider.HollowFactory;
4
+import com.netflix.hollow.core.read.dataaccess.HollowTypeDataAccess;
5
+import com.netflix.hollow.api.custom.HollowTypeAPI;
6
+
7
+@SuppressWarnings("all")
8
+public class StringHollowFactory<T extends HString> extends HollowFactory<T> {
9
+
10
+    @Override
11
+    public T newHollowObject(HollowTypeDataAccess dataAccess, HollowTypeAPI typeAPI, int ordinal) {
12
+        return (T)new HString(((StringTypeAPI)typeAPI).getDelegateLookupImpl(), ordinal);
13
+    }
14
+
15
+    @Override
16
+    public T newCachedHollowObject(HollowTypeDataAccess dataAccess, HollowTypeAPI typeAPI, int ordinal) {
17
+        return (T)new HString(new StringDelegateCachedImpl((StringTypeAPI)typeAPI, ordinal), ordinal);
18
+    }
19
+
20
+}
0 21
\ No newline at end of file
1 22
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.consumer.HollowConsumer;
4
+import com.netflix.hollow.api.consumer.index.AbstractHollowUniqueKeyIndex;
5
+import com.netflix.hollow.api.consumer.index.HollowUniqueKeyIndex;
6
+import com.netflix.hollow.core.schema.HollowObjectSchema;
7
+
8
+@SuppressWarnings("all")
9
+public class StringPrimaryKeyIndex extends AbstractHollowUniqueKeyIndex<TokensAPI, HString> implements HollowUniqueKeyIndex<HString> {
10
+
11
+    public StringPrimaryKeyIndex(HollowConsumer consumer) {
12
+        this(consumer, true);
13
+    }
14
+
15
+    public StringPrimaryKeyIndex(HollowConsumer consumer, boolean isListenToDataRefresh) {
16
+        this(consumer, isListenToDataRefresh, ((HollowObjectSchema)consumer.getStateEngine().getNonNullSchema("String")).getPrimaryKey().getFieldPaths());
17
+    }
18
+
19
+    public StringPrimaryKeyIndex(HollowConsumer consumer, String... fieldPaths) {
20
+        this(consumer, true, fieldPaths);
21
+    }
22
+
23
+    public StringPrimaryKeyIndex(HollowConsumer consumer, boolean isListenToDataRefresh, String... fieldPaths) {
24
+        super(consumer, "String", isListenToDataRefresh, fieldPaths);
25
+    }
26
+
27
+    @Override
28
+    public HString findMatch(Object... keys) {
29
+        int ordinal = idx.getMatchingOrdinal(keys);
30
+        if(ordinal == -1)
31
+            return null;
32
+        return api.getHString(ordinal);
33
+    }
34
+
35
+}
0 36
\ No newline at end of file
1 37
new file mode 100644
... ...
@@ -0,0 +1,40 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.custom.HollowObjectTypeAPI;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+
6
+@SuppressWarnings("all")
7
+public class StringTypeAPI extends HollowObjectTypeAPI {
8
+
9
+    private final StringDelegateLookupImpl delegateLookupImpl;
10
+
11
+    public StringTypeAPI(TokensAPI api, HollowObjectTypeDataAccess typeDataAccess) {
12
+        super(api, typeDataAccess, new String[] {
13
+            "value"
14
+        });
15
+        this.delegateLookupImpl = new StringDelegateLookupImpl(this);
16
+    }
17
+
18
+    public String getValue(int ordinal) {
19
+        if(fieldIndex[0] == -1)
20
+            return missingDataHandler().handleString("String", ordinal, "value");
21
+        boxedFieldAccessSampler.recordFieldAccess(fieldIndex[0]);
22
+        return getTypeDataAccess().readString(ordinal, fieldIndex[0]);
23
+    }
24
+
25
+    public boolean isValueEqual(int ordinal, String testValue) {
26
+        if(fieldIndex[0] == -1)
27
+            return missingDataHandler().handleStringEquals("String", ordinal, "value", testValue);
28
+        return getTypeDataAccess().isStringFieldEqual(ordinal, fieldIndex[0], testValue);
29
+    }
30
+
31
+    public StringDelegateLookupImpl getDelegateLookupImpl() {
32
+        return delegateLookupImpl;
33
+    }
34
+
35
+    @Override
36
+    public TokensAPI getAPI() {
37
+        return (TokensAPI) api;
38
+    }
39
+
40
+}
0 41
\ No newline at end of file
1 42
new file mode 100644
... ...
@@ -0,0 +1,56 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.HollowObject;
4
+import com.netflix.hollow.core.schema.HollowObjectSchema;
5
+
6
+import com.netflix.hollow.tools.stringifier.HollowRecordStringifier;
7
+
8
+@SuppressWarnings("all")
9
+public class Token extends HollowObject {
10
+
11
+    public Token(TokenDelegate delegate, int ordinal) {
12
+        super(delegate, ordinal);
13
+    }
14
+
15
+    public HString getKey() {
16
+        int refOrdinal = delegate().getKeyOrdinal(ordinal);
17
+        if(refOrdinal == -1)
18
+            return null;
19
+        return  api().getHString(refOrdinal);
20
+    }
21
+
22
+    public HString getSubjectUid() {
23
+        int refOrdinal = delegate().getSubjectUidOrdinal(ordinal);
24
+        if(refOrdinal == -1)
25
+            return null;
26
+        return  api().getHString(refOrdinal);
27
+    }
28
+
29
+    public HString getSubjectDomain() {
30
+        int refOrdinal = delegate().getSubjectDomainOrdinal(ordinal);
31
+        if(refOrdinal == -1)
32
+            return null;
33
+        return  api().getHString(refOrdinal);
34
+    }
35
+
36
+    public long getExpiresTimestamp() {
37
+        return delegate().getExpiresTimestamp(ordinal);
38
+    }
39
+
40
+    public Long getExpiresTimestampBoxed() {
41
+        return delegate().getExpiresTimestampBoxed(ordinal);
42
+    }
43
+
44
+    public TokensAPI api() {
45
+        return typeApi().getAPI();
46
+    }
47
+
48
+    public TokenTypeAPI typeApi() {
49
+        return delegate().getTypeAPI();
50
+    }
51
+
52
+    protected TokenDelegate delegate() {
53
+        return (TokenDelegate)delegate;
54
+    }
55
+
56
+}
0 57
\ No newline at end of file
1 58
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.consumer.HollowConsumer;
4
+import com.netflix.hollow.api.consumer.data.AbstractHollowDataAccessor;
5
+import com.netflix.hollow.core.index.key.PrimaryKey;
6
+import com.netflix.hollow.core.read.engine.HollowReadStateEngine;
7
+
8
+@SuppressWarnings("all")
9
+public class TokenDataAccessor extends AbstractHollowDataAccessor<Token> {
10
+
11
+    public static final String TYPE = "Token";
12
+    private TokensAPI api;
13
+
14
+    public TokenDataAccessor(HollowConsumer consumer) {
15
+        super(consumer, TYPE);
16
+        this.api = (TokensAPI)consumer.getAPI();
17
+    }
18
+
19
+    public TokenDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api) {
20
+        super(rStateEngine, TYPE);
21
+        this.api = api;
22
+    }
23
+
24
+    public TokenDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api, String ... fieldPaths) {
25
+        super(rStateEngine, TYPE, fieldPaths);
26
+        this.api = api;
27
+    }
28
+
29
+    public TokenDataAccessor(HollowReadStateEngine rStateEngine, TokensAPI api, PrimaryKey primaryKey) {
30
+        super(rStateEngine, TYPE, primaryKey);
31
+        this.api = api;
32
+    }
33
+
34
+    @Override public Token getRecord(int ordinal){
35
+        return api.getToken(ordinal);
36
+    }
37
+
38
+}
0 39
\ No newline at end of file
1 40
new file mode 100644
... ...
@@ -0,0 +1,21 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectDelegate;
4
+
5
+
6
+@SuppressWarnings("all")
7
+public interface TokenDelegate extends HollowObjectDelegate {
8
+
9
+    public int getKeyOrdinal(int ordinal);
10
+
11
+    public int getSubjectUidOrdinal(int ordinal);
12
+
13
+    public int getSubjectDomainOrdinal(int ordinal);
14
+
15
+    public long getExpiresTimestamp(int ordinal);
16
+
17
+    public Long getExpiresTimestampBoxed(int ordinal);
18
+
19
+    public TokenTypeAPI getTypeAPI();
20
+
21
+}
0 22
\ No newline at end of file
1 23
new file mode 100644
... ...
@@ -0,0 +1,66 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectAbstractDelegate;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+import com.netflix.hollow.core.schema.HollowObjectSchema;
6
+import com.netflix.hollow.api.custom.HollowTypeAPI;
7
+import com.netflix.hollow.api.objects.delegate.HollowCachedDelegate;
8
+
9
+@SuppressWarnings("all")
10
+public class TokenDelegateCachedImpl extends HollowObjectAbstractDelegate implements HollowCachedDelegate, TokenDelegate {
11
+
12
+    private final int keyOrdinal;
13
+    private final int subjectUidOrdinal;
14
+    private final int subjectDomainOrdinal;
15
+    private final Long expiresTimestamp;
16
+    private TokenTypeAPI typeAPI;
17
+
18
+    public TokenDelegateCachedImpl(TokenTypeAPI typeAPI, int ordinal) {
19
+        this.keyOrdinal = typeAPI.getKeyOrdinal(ordinal);
20
+        this.subjectUidOrdinal = typeAPI.getSubjectUidOrdinal(ordinal);
21
+        this.subjectDomainOrdinal = typeAPI.getSubjectDomainOrdinal(ordinal);
22
+        this.expiresTimestamp = typeAPI.getExpiresTimestampBoxed(ordinal);
23
+        this.typeAPI = typeAPI;
24
+    }
25
+
26
+    public int getKeyOrdinal(int ordinal) {
27
+        return keyOrdinal;
28
+    }
29
+
30
+    public int getSubjectUidOrdinal(int ordinal) {
31
+        return subjectUidOrdinal;
32
+    }
33
+
34
+    public int getSubjectDomainOrdinal(int ordinal) {
35
+        return subjectDomainOrdinal;
36
+    }
37
+
38
+    public long getExpiresTimestamp(int ordinal) {
39
+        if(expiresTimestamp == null)
40
+            return Long.MIN_VALUE;
41
+        return expiresTimestamp.longValue();
42
+    }
43
+
44
+    public Long getExpiresTimestampBoxed(int ordinal) {
45
+        return expiresTimestamp;
46
+    }
47
+
48
+    @Override
49
+    public HollowObjectSchema getSchema() {
50
+        return typeAPI.getTypeDataAccess().getSchema();
51
+    }
52
+
53
+    @Override
54
+    public HollowObjectTypeDataAccess getTypeDataAccess() {
55
+        return typeAPI.getTypeDataAccess();
56
+    }
57
+
58
+    public TokenTypeAPI getTypeAPI() {
59
+        return typeAPI;
60
+    }
61
+
62
+    public void updateTypeAPI(HollowTypeAPI typeAPI) {
63
+        this.typeAPI = (TokenTypeAPI) typeAPI;
64
+    }
65
+
66
+}
0 67
\ No newline at end of file
1 68
new file mode 100644
... ...
@@ -0,0 +1,50 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.delegate.HollowObjectAbstractDelegate;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+import com.netflix.hollow.core.schema.HollowObjectSchema;
6
+
7
+@SuppressWarnings("all")
8
+public class TokenDelegateLookupImpl extends HollowObjectAbstractDelegate implements TokenDelegate {
9
+
10
+    private final TokenTypeAPI typeAPI;
11
+
12
+    public TokenDelegateLookupImpl(TokenTypeAPI typeAPI) {
13
+        this.typeAPI = typeAPI;
14
+    }
15
+
16
+    public int getKeyOrdinal(int ordinal) {
17
+        return typeAPI.getKeyOrdinal(ordinal);
18
+    }
19
+
20
+    public int getSubjectUidOrdinal(int ordinal) {
21
+        return typeAPI.getSubjectUidOrdinal(ordinal);
22
+    }
23
+
24
+    public int getSubjectDomainOrdinal(int ordinal) {
25
+        return typeAPI.getSubjectDomainOrdinal(ordinal);
26
+    }
27
+
28
+    public long getExpiresTimestamp(int ordinal) {
29
+        return typeAPI.getExpiresTimestamp(ordinal);
30
+    }
31
+
32
+    public Long getExpiresTimestampBoxed(int ordinal) {
33
+        return typeAPI.getExpiresTimestampBoxed(ordinal);
34
+    }
35
+
36
+    public TokenTypeAPI getTypeAPI() {
37
+        return typeAPI;
38
+    }
39
+
40
+    @Override
41
+    public HollowObjectSchema getSchema() {
42
+        return typeAPI.getTypeDataAccess().getSchema();
43
+    }
44
+
45
+    @Override
46
+    public HollowObjectTypeDataAccess getTypeDataAccess() {
47
+        return typeAPI.getTypeDataAccess();
48
+    }
49
+
50
+}
0 51
\ No newline at end of file
1 52
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.objects.provider.HollowFactory;
4
+import com.netflix.hollow.core.read.dataaccess.HollowTypeDataAccess;
5
+import com.netflix.hollow.api.custom.HollowTypeAPI;
6
+
7
+@SuppressWarnings("all")
8
+public class TokenHollowFactory<T extends Token> extends HollowFactory<T> {
9
+
10
+    @Override
11
+    public T newHollowObject(HollowTypeDataAccess dataAccess, HollowTypeAPI typeAPI, int ordinal) {
12
+        return (T)new Token(((TokenTypeAPI)typeAPI).getDelegateLookupImpl(), ordinal);
13
+    }
14
+
15
+    @Override
16
+    public T newCachedHollowObject(HollowTypeDataAccess dataAccess, HollowTypeAPI typeAPI, int ordinal) {
17
+        return (T)new Token(new TokenDelegateCachedImpl((TokenTypeAPI)typeAPI, ordinal), ordinal);
18
+    }
19
+
20
+}
0 21
\ No newline at end of file
1 22
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.consumer.HollowConsumer;
4
+import com.netflix.hollow.api.consumer.index.AbstractHollowUniqueKeyIndex;
5
+import com.netflix.hollow.api.consumer.index.HollowUniqueKeyIndex;
6
+import com.netflix.hollow.core.schema.HollowObjectSchema;
7
+
8
+@SuppressWarnings("all")
9
+public class TokenPrimaryKeyIndex extends AbstractHollowUniqueKeyIndex<TokensAPI, Token> implements HollowUniqueKeyIndex<Token> {
10
+
11
+    public TokenPrimaryKeyIndex(HollowConsumer consumer) {
12
+        this(consumer, true);
13
+    }
14
+
15
+    public TokenPrimaryKeyIndex(HollowConsumer consumer, boolean isListenToDataRefresh) {
16
+        this(consumer, isListenToDataRefresh, ((HollowObjectSchema)consumer.getStateEngine().getNonNullSchema("Token")).getPrimaryKey().getFieldPaths());
17
+    }
18
+
19
+    public TokenPrimaryKeyIndex(HollowConsumer consumer, String... fieldPaths) {
20
+        this(consumer, true, fieldPaths);
21
+    }
22
+
23
+    public TokenPrimaryKeyIndex(HollowConsumer consumer, boolean isListenToDataRefresh, String... fieldPaths) {
24
+        super(consumer, "Token", isListenToDataRefresh, fieldPaths);
25
+    }
26
+
27
+    @Override
28
+    public Token findMatch(Object... keys) {
29
+        int ordinal = idx.getMatchingOrdinal(keys);
30
+        if(ordinal == -1)
31
+            return null;
32
+        return api.getToken(ordinal);
33
+    }
34
+
35
+}
0 36
\ No newline at end of file
1 37
new file mode 100644
... ...
@@ -0,0 +1,81 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.custom.HollowObjectTypeAPI;
4
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
5
+
6
+@SuppressWarnings("all")
7
+public class TokenTypeAPI extends HollowObjectTypeAPI {
8
+
9
+    private final TokenDelegateLookupImpl delegateLookupImpl;
10
+
11
+    public TokenTypeAPI(TokensAPI api, HollowObjectTypeDataAccess typeDataAccess) {
12
+        super(api, typeDataAccess, new String[] {
13
+            "key",
14
+            "subjectUid",
15
+            "subjectDomain",
16
+            "expiresTimestamp"
17
+        });
18
+        this.delegateLookupImpl = new TokenDelegateLookupImpl(this);
19
+    }
20
+
21
+    public int getKeyOrdinal(int ordinal) {
22
+        if(fieldIndex[0] == -1)
23
+            return missingDataHandler().handleReferencedOrdinal("Token", ordinal, "key");
24
+        return getTypeDataAccess().readOrdinal(ordinal, fieldIndex[0]);
25
+    }
26
+
27
+    public StringTypeAPI getKeyTypeAPI() {
28
+        return getAPI().getStringTypeAPI();
29
+    }
30
+
31
+    public int getSubjectUidOrdinal(int ordinal) {
32
+        if(fieldIndex[1] == -1)
33
+            return missingDataHandler().handleReferencedOrdinal("Token", ordinal, "subjectUid");
34
+        return getTypeDataAccess().readOrdinal(ordinal, fieldIndex[1]);
35
+    }
36
+
37
+    public StringTypeAPI getSubjectUidTypeAPI() {
38
+        return getAPI().getStringTypeAPI();
39
+    }
40
+
41
+    public int getSubjectDomainOrdinal(int ordinal) {
42
+        if(fieldIndex[2] == -1)
43
+            return missingDataHandler().handleReferencedOrdinal("Token", ordinal, "subjectDomain");
44
+        return getTypeDataAccess().readOrdinal(ordinal, fieldIndex[2]);
45
+    }
46
+
47
+    public StringTypeAPI getSubjectDomainTypeAPI() {
48
+        return getAPI().getStringTypeAPI();
49
+    }
50
+
51
+    public long getExpiresTimestamp(int ordinal) {
52
+        if(fieldIndex[3] == -1)
53
+            return missingDataHandler().handleLong("Token", ordinal, "expiresTimestamp");
54
+        return getTypeDataAccess().readLong(ordinal, fieldIndex[3]);
55
+    }
56
+
57
+    public Long getExpiresTimestampBoxed(int ordinal) {
58
+        long l;
59
+        if(fieldIndex[3] == -1) {
60
+            l = missingDataHandler().handleLong("Token", ordinal, "expiresTimestamp");
61
+        } else {
62
+            boxedFieldAccessSampler.recordFieldAccess(fieldIndex[3]);
63
+            l = getTypeDataAccess().readLong(ordinal, fieldIndex[3]);
64
+        }
65
+        if(l == Long.MIN_VALUE)
66
+            return null;
67
+        return Long.valueOf(l);
68
+    }
69
+
70
+
71
+
72
+    public TokenDelegateLookupImpl getDelegateLookupImpl() {
73
+        return delegateLookupImpl;
74
+    }
75
+
76
+    @Override
77
+    public TokensAPI getAPI() {
78
+        return (TokensAPI) api;
79
+    }
80
+
81
+}
0 82
\ No newline at end of file
1 83
new file mode 100644
... ...
@@ -0,0 +1,142 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import java.util.Collection;
4
+import java.util.Collections;
5
+import java.util.Set;
6
+import java.util.Map;
7
+import com.netflix.hollow.api.consumer.HollowConsumerAPI;
8
+import com.netflix.hollow.api.custom.HollowAPI;
9
+import com.netflix.hollow.core.read.dataaccess.HollowDataAccess;
10
+import com.netflix.hollow.core.read.dataaccess.HollowTypeDataAccess;
11
+import com.netflix.hollow.core.read.dataaccess.HollowObjectTypeDataAccess;
12
+import com.netflix.hollow.core.read.dataaccess.HollowListTypeDataAccess;
13
+import com.netflix.hollow.core.read.dataaccess.HollowSetTypeDataAccess;
14
+import com.netflix.hollow.core.read.dataaccess.HollowMapTypeDataAccess;
15
+import com.netflix.hollow.core.read.dataaccess.missing.HollowObjectMissingDataAccess;
16
+import com.netflix.hollow.core.read.dataaccess.missing.HollowListMissingDataAccess;
17
+import com.netflix.hollow.core.read.dataaccess.missing.HollowSetMissingDataAccess;
18
+import com.netflix.hollow.core.read.dataaccess.missing.HollowMapMissingDataAccess;
19
+import com.netflix.hollow.api.objects.provider.HollowFactory;
20
+import com.netflix.hollow.api.objects.provider.HollowObjectProvider;
21
+import com.netflix.hollow.api.objects.provider.HollowObjectCacheProvider;
22
+import com.netflix.hollow.api.objects.provider.HollowObjectFactoryProvider;
23
+import com.netflix.hollow.api.sampling.HollowObjectCreationSampler;
24
+import com.netflix.hollow.api.sampling.HollowSamplingDirector;
25
+import com.netflix.hollow.api.sampling.SampleResult;
26
+import com.netflix.hollow.core.util.AllHollowRecordCollection;
27
+
28
+@SuppressWarnings("all")
29
+public class TokensAPI extends HollowAPI  {
30
+
31
+    private final HollowObjectCreationSampler objectCreationSampler;
32
+
33
+    private final StringTypeAPI stringTypeAPI;
34
+    private final TokenTypeAPI tokenTypeAPI;
35
+
36
+    private final HollowObjectProvider stringProvider;
37
+    private final HollowObjectProvider tokenProvider;
38
+
39
+    public TokensAPI(HollowDataAccess dataAccess) {
40
+        this(dataAccess, Collections.<String>emptySet());
41
+    }
42
+
43
+    public TokensAPI(HollowDataAccess dataAccess, Set<String> cachedTypes) {
44
+        this(dataAccess, cachedTypes, Collections.<String, HollowFactory<?>>emptyMap());
45
+    }
46
+
47
+    public TokensAPI(HollowDataAccess dataAccess, Set<String> cachedTypes, Map<String, HollowFactory<?>> factoryOverrides) {
48
+        this(dataAccess, cachedTypes, factoryOverrides, null);
49
+    }
50
+
51
+    public TokensAPI(HollowDataAccess dataAccess, Set<String> cachedTypes, Map<String, HollowFactory<?>> factoryOverrides, TokensAPI previousCycleAPI) {
52
+        super(dataAccess);
53
+        HollowTypeDataAccess typeDataAccess;
54
+        HollowFactory factory;
55
+
56
+        objectCreationSampler = new HollowObjectCreationSampler("String","Token");
57
+
58
+        typeDataAccess = dataAccess.getTypeDataAccess("String");
59
+        if(typeDataAccess != null) {
60
+            stringTypeAPI = new StringTypeAPI(this, (HollowObjectTypeDataAccess)typeDataAccess);
61
+        } else {
62
+            stringTypeAPI = new StringTypeAPI(this, new HollowObjectMissingDataAccess(dataAccess, "String"));
63
+        }
64
+        addTypeAPI(stringTypeAPI);
65
+        factory = factoryOverrides.get("String");
66
+        if(factory == null)
67
+            factory = new StringHollowFactory();
68
+        if(cachedTypes.contains("String")) {
69
+            HollowObjectCacheProvider previousCacheProvider = null;
70
+            if(previousCycleAPI != null && (previousCycleAPI.stringProvider instanceof HollowObjectCacheProvider))
71
+                previousCacheProvider = (HollowObjectCacheProvider) previousCycleAPI.stringProvider;
72
+            stringProvider = new HollowObjectCacheProvider(typeDataAccess, stringTypeAPI, factory, previousCacheProvider);
73
+        } else {
74
+            stringProvider = new HollowObjectFactoryProvider(typeDataAccess, stringTypeAPI, factory);
75
+        }
76
+
77
+        typeDataAccess = dataAccess.getTypeDataAccess("Token");
78
+        if(typeDataAccess != null) {
79
+            tokenTypeAPI = new TokenTypeAPI(this, (HollowObjectTypeDataAccess)typeDataAccess);
80
+        } else {
81
+            tokenTypeAPI = new TokenTypeAPI(this, new HollowObjectMissingDataAccess(dataAccess, "Token"));
82
+        }
83
+        addTypeAPI(tokenTypeAPI);
84
+        factory = factoryOverrides.get("Token");
85
+        if(factory == null)
86
+            factory = new TokenHollowFactory();
87
+        if(cachedTypes.contains("Token")) {
88
+            HollowObjectCacheProvider previousCacheProvider = null;
89
+            if(previousCycleAPI != null && (previousCycleAPI.tokenProvider instanceof HollowObjectCacheProvider))
90
+                previousCacheProvider = (HollowObjectCacheProvider) previousCycleAPI.tokenProvider;
91
+            tokenProvider = new HollowObjectCacheProvider(typeDataAccess, tokenTypeAPI, factory, previousCacheProvider);
92
+        } else {
93
+            tokenProvider = new HollowObjectFactoryProvider(typeDataAccess, tokenTypeAPI, factory);
94
+        }
95
+
96
+    }
97
+
98
+    public void detachCaches() {
99
+        if(stringProvider instanceof HollowObjectCacheProvider)
100
+            ((HollowObjectCacheProvider)stringProvider).detach();
101
+        if(tokenProvider instanceof HollowObjectCacheProvider)
102
+            ((HollowObjectCacheProvider)tokenProvider).detach();
103
+    }
104
+
105
+    public StringTypeAPI getStringTypeAPI() {
106
+        return stringTypeAPI;
107
+    }
108
+    public TokenTypeAPI getTokenTypeAPI() {
109
+        return tokenTypeAPI;
110
+    }
111
+    public Collection<HString> getAllHString() {
112
+        return new AllHollowRecordCollection<HString>(getDataAccess().getTypeDataAccess("String").getTypeState()) {
113
+            protected HString getForOrdinal(int ordinal) {
114
+                return getHString(ordinal);
115
+            }
116
+        };
117
+    }
118
+    public HString getHString(int ordinal) {
119
+        objectCreationSampler.recordCreation(0);
120
+        return (HString)stringProvider.getHollowObject(ordinal);
121
+    }
122
+    public Collection<Token> getAllToken() {
123
+        return new AllHollowRecordCollection<Token>(getDataAccess().getTypeDataAccess("Token").getTypeState()) {
124
+            protected Token getForOrdinal(int ordinal) {
125
+                return getToken(ordinal);
126
+            }
127
+        };
128
+    }
129
+    public Token getToken(int ordinal) {
130
+        objectCreationSampler.recordCreation(1);
131
+        return (Token)tokenProvider.getHollowObject(ordinal);
132
+    }
133
+    public void setSamplingDirector(HollowSamplingDirector director) {
134
+        super.setSamplingDirector(director);
135
+        objectCreationSampler.setSamplingDirector(director);
136
+    }
137
+
138
+    public Collection<SampleResult> getObjectCreationSamplingResults() {
139
+        return objectCreationSampler.getSampleResults();
140
+    }
141
+
142
+}
0 143
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.client.HollowAPIFactory;
4
+import com.netflix.hollow.api.custom.HollowAPI;
5
+import com.netflix.hollow.api.objects.provider.HollowFactory;
6
+import com.netflix.hollow.core.read.dataaccess.HollowDataAccess;
7
+import java.util.Collections;
8
+import java.util.Set;
9
+
10
+@SuppressWarnings("all")
11
+public class TokensAPIFactory implements HollowAPIFactory {
12
+
13
+    private final Set<String> cachedTypes;
14
+
15
+    public TokensAPIFactory() {
16
+        this(Collections.<String>emptySet());
17
+    }
18
+
19
+    public TokensAPIFactory(Set<String> cachedTypes) {
20
+        this.cachedTypes = cachedTypes;
21
+    }
22
+
23
+    @Override
24
+    public HollowAPI createAPI(HollowDataAccess dataAccess) {
25
+        return new TokensAPI(dataAccess, cachedTypes);
26
+    }
27
+
28
+    @Override
29
+    public HollowAPI createAPI(HollowDataAccess dataAccess, HollowAPI previousCycleAPI) {
30
+        if (!(previousCycleAPI instanceof TokensAPI)) {
31
+            throw new ClassCastException(previousCycleAPI.getClass() + " not instance of TokensAPI");        }
32
+        return new TokensAPI(dataAccess, cachedTypes, Collections.<String, HollowFactory<?>>emptyMap(), (TokensAPI) previousCycleAPI);
33
+    }
34
+
35
+}
0 36
\ No newline at end of file
1 37
new file mode 100644
... ...
@@ -0,0 +1,44 @@
1
+package net.bluemind.authentication.service.tokens;
2
+
3
+import com.netflix.hollow.api.consumer.HollowConsumer;
4
+import com.netflix.hollow.core.index.HollowHashIndexResult;
5
+import java.util.Collections;
6
+import java.lang.Iterable;
7
+import com.netflix.hollow.api.consumer.index.AbstractHollowHashIndex;
8
+import com.netflix.hollow.api.consumer.data.AbstractHollowOrdinalIterable;
9
+
10
+
11
+@SuppressWarnings("all")
12
+public class TokensAPIHashIndex extends AbstractHollowHashIndex<TokensAPI> {
13
+
14
+    public TokensAPIHashIndex(HollowConsumer consumer, String queryType, String selectFieldPath, String... matchFieldPaths) {
15
+        super(consumer, true, queryType, selectFieldPath, matchFieldPaths);
16
+    }
17
+
18
+    public TokensAPIHashIndex(HollowConsumer consumer, boolean isListenToDataRefresh, String queryType, String selectFieldPath, String... matchFieldPaths) {
19
+        super(consumer, isListenToDataRefresh, queryType, selectFieldPath, matchFieldPaths);
20
+    }
21
+
22
+    public Iterable<HString> findStringMatches(Object... keys) {
23
+        HollowHashIndexResult matches = idx.findMatches(keys);
24
+        if(matches == null) return Collections.emptySet();
25
+
26
+        return new AbstractHollowOrdinalIterable<HString>(matches.iterator()) {
27
+            public HString getData(int ordinal) {
28
+                return api.getHString(ordinal);
29
+            }
30
+        };
31
+    }
32
+
33
+    public Iterable<Token> findTokenMatches(Object... keys) {
34
+        HollowHashIndexResult matches = idx.findMatches(keys);
35
+        if(matches == null) return Collections.emptySet();
36
+
37
+        return new AbstractHollowOrdinalIterable<Token>(matches.iterator()) {
38
+            public Token getData(int ordinal) {
39
+                return api.getToken(ordinal);
40
+            }
41
+        };
42
+    }
43
+
44
+}
0 45
\ No newline at end of file
... ...
@@ -6,6 +6,9 @@
6 6
       <endpoint
7 7
             api="net.bluemind.authentication.api.IAuthentication">
8 8
       </endpoint>
9
+      <endpoint
10
+            api="net.bluemind.authentication.api.ISecurityToken">
11
+      </endpoint>
9 12
    </extension>
10 13
    <extension
11 14
          point="net.bluemind.core.rest.serviceFactory">
... ...
@@ -15,6 +18,9 @@
15 18
       <serviceFactory
16 19
             class="net.bluemind.authentication.service.InCoreAuthenticationFactory">
17 20
       </serviceFactory>
21
+      <serviceFactory
22
+            class="net.bluemind.authentication.service.SecurityTokenService$Factory">
23
+      </serviceFactory>
18 24
    </extension>
19 25
    <extension
20 26
          point="net.bluemind.core.rest.apiEndpoint">
... ...
@@ -34,5 +40,18 @@
34 40
             impl="net.bluemind.authentication.service.internal.AuthContextUserHook">
35 41
       </hook>
36 42
    </extension>
43
+   <extension
44
+         point="net.bluemind.core.sessions.provider">
45
+      <provider
46
+            impl="net.bluemind.authentication.service.TokenSessionProvider"
47
+            priority="42">
48
+      </provider>
49
+   </extension>
50
+   <extension
51
+         point="net.bluemind.lib.vertx.verticles">
52
+      <verticle
53
+            impl="net.bluemind.authentication.service.tokens.TokenExpireVerticle$Factory">
54
+      </verticle>
55
+   </extension>
37 56
 
38 57
 </plugin>
39 58
new file mode 100644
... ...
@@ -0,0 +1,94 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2019
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.service;
20
+
21
+import java.util.Arrays;
22
+
23
+import org.slf4j.Logger;
24
+import org.slf4j.LoggerFactory;
25
+
26
+import net.bluemind.authentication.api.ISecurityToken;
27
+import net.bluemind.authentication.service.tokens.TokensStore;
28
+import net.bluemind.core.api.fault.ServerFault;
29
+import net.bluemind.core.context.SecurityContext;
30
+import net.bluemind.core.rest.BmContext;
31
+import net.bluemind.core.rest.ServerSideServiceProvider;
32
+import net.bluemind.core.sessions.Sessions;
33
+
34
+public class SecurityTokenService implements ISecurityToken {
35
+
36
+	private static final Logger logger = LoggerFactory.getLogger(SecurityTokenService.class);
37
+
38
+	private final String sid;
39
+
40
+	public SecurityTokenService(BmContext context, String sid) {
41
+		this.sid = sid;
42
+	}
43
+
44
+	@Override
45
+	public void upgrade() {
46
+		SecurityContext sec = Sessions.get().getIfPresent(sid);
47
+		if (sec == null) {
48
+			throw ServerFault.notFound("sid '" + sid + "' is missing");
49
+		}
50
+		logger.info("{} (Upgrade token)", sid);
51
+		TokensStore.get().add(new Token(sid, sec.getSubject(), sec.getContainerUid()));
52
+	}
53
+
54
+	@Override
55
+	public void renew() {
56
+		Token token = TokensStore.get().byKey(sid);
57
+		if (token == null) {
58
+			throw ServerFault.notFound("token '" + sid + "' is missing");
59
+		}
60
+		token.renew();
61
+	}
62
+
63
+	@Override
64
+	public void destroy() {
65
+		Token token = TokensStore.get().remove(sid);
66
+		if (token == null) {
67
+			logger.warn("Token " + sid + " was unknown");
68
+		} else {
69
+			Sessions.get().invalidate(sid);
70
+		}
71
+	}
72
+
73
+	public static class Factory implements ServerSideServiceProvider.IServerSideServiceFactory<ISecurityToken> {
74
+
75
+		@Override
76
+		public Class<ISecurityToken> factoryClass() {
77
+			return ISecurityToken.class;
78
+		}
79
+
80
+		@Override
81
+		public ISecurityToken instance(BmContext context, String... params) throws ServerFault {
82
+			if (params.length != 1) {
83
+				throw new ServerFault("sid parameter expected, params are " + Arrays.toString(params));
84
+			}
85
+			String sid = params[0];
86
+			if (!context.getSecurityContext().isAdmin() && !sid.equals(context.getSecurityContext().getSessionId())) {
87
+				throw new ServerFault("Admin or active session required.");
88
+			}
89
+			return new SecurityTokenService(context, params[0]);
90
+		}
91
+
92
+	}
93
+
94
+}
0 95
new file mode 100644
... ...
@@ -0,0 +1,46 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2019
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.service;
20
+
21
+import java.util.concurrent.TimeUnit;
22
+
23
+import com.netflix.hollow.core.write.objectmapper.HollowPrimaryKey;
24
+
25
+@HollowPrimaryKey(fields = { "key" })
26
+public class Token {
27
+
28
+	public String key;
29
+
30
+	public String subjectUid;
31
+
32
+	public String subjectDomain;
33
+
34
+	public long expiresTimestamp;
35
+
36
+	public Token(String key, String subject, String subjectDomain) {
37
+		this.key = key;
38
+		this.subjectUid = subject;
39
+		this.subjectDomain = subjectDomain;
40
+		expiresTimestamp = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7);
41
+	}
42
+
43
+	public void renew() {
44
+		expiresTimestamp = expiresTimestamp + TimeUnit.DAYS.toMillis(7);
45
+	}
46
+}
0 47
\ No newline at end of file
1 48
new file mode 100644
... ...
@@ -0,0 +1,57 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2019
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.service;
20
+
21
+import java.util.Date;
22
+import java.util.Optional;
23
+
24
+import org.slf4j.Logger;
25
+import org.slf4j.LoggerFactory;
26
+
27
+import net.bluemind.authentication.api.incore.IInCoreAuthentication;
28
+import net.bluemind.authentication.service.tokens.TokensStore;
29
+import net.bluemind.core.context.SecurityContext;
30
+import net.bluemind.core.rest.ServerSideServiceProvider;
31
+import net.bluemind.core.sessions.ISessionsProvider;
32
+
33
+public class TokenSessionProvider implements ISessionsProvider {
34
+
35
+	private static final Logger logger = LoggerFactory.getLogger(TokenSessionProvider.class);
36
+
37
+	private IInCoreAuthentication coreAuth;
38
+
39
+	public TokenSessionProvider() {
40
+		ServerSideServiceProvider apis = ServerSideServiceProvider.getProvider(SecurityContext.SYSTEM);
41
+		this.coreAuth = apis.instance(IInCoreAuthentication.class);
42
+	}
43
+
44
+	@Override
45
+	public Optional<SecurityContext> get(String token) {
46
+		return Optional.ofNullable(TokensStore.get().byKey(token)).map(tok -> {
47
+			if (tok.expiresTimestamp < System.currentTimeMillis()) {
48
+				logger.warn("[{}@{}] Token {} is expired since {}", tok.subjectUid, tok.subjectDomain, tok.key,
49
+						new Date(tok.expiresTimestamp));
50
+				return null;
51
+			}
52
+			logger.info("[{}@{}] Rebuilding context for token {}", tok.subjectUid, tok.subjectDomain, tok.key);
53
+			return coreAuth.buildContext(tok.subjectDomain, tok.subjectUid);
54
+		});
55
+	}
56
+
57
+}
0 58
new file mode 100644
... ...
@@ -0,0 +1,51 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2018
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.service.internal;
20
+
21
+import java.io.IOException;
22
+
23
+import com.netflix.hollow.api.codegen.HollowAPIGenerator;
24
+import com.netflix.hollow.core.write.HollowWriteStateEngine;
25
+import com.netflix.hollow.core.write.objectmapper.HollowObjectMapper;
26
+
27
+import net.bluemind.authentication.service.Token;
28
+import net.bluemind.authentication.service.tokens.TokensStore;
29
+
30
+public class GenerateConsumerApi {
31
+
32
+	public static void main(String[] args) throws IOException {
33
+		HollowWriteStateEngine writeEngine = new HollowWriteStateEngine();
34
+		HollowObjectMapper mapper = new HollowObjectMapper(writeEngine);
35
+		mapper.initializeTypeState(Token.class);
36
+
37
+		HollowAPIGenerator generator = new HollowAPIGenerator.Builder().withAPIClassname("TokensAPI")
38
+				// .withDestination(
39
+				// "/Users/tom/git/bluemind-all/open/parent/directory/net.bluemind.directory.hollow.datamodel.consumer/hollow-generated/")
40
+				// .withDestination(
41
+				// "/Users/tf/dev/projects/bluemind-mapi/open/parent/directory/net.bluemind.directory.hollow.datamodel.consumer/hollow-generated")
42
+				.withDestination(
43
+						"/Users/tom/git/bluemind-all/open/parent/authentication/net.bluemind.authentication.service/hollow-generated")
44
+				.withPackageName(TokensStore.class.getPackage().getName()).withDataModel(writeEngine).build();
45
+		// "/Users/david/devel/bluemind/open/parent/directory/net.bluemind.directory.hollow.datamodel.consumer/hollow-generated")
46
+		// .withPackageName(Activator.class.getPackage().getName()).withDataModel(writeEngine).build();
47
+
48
+		generator.generateSourceFiles();
49
+	}
50
+
51
+}
0 52
new file mode 100644
... ...
@@ -0,0 +1,51 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2019
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.authentication.service.tokens;
20
+
21
+import java.util.concurrent.TimeUnit;
22