Commit c32ede69 authored by Valentin Suhnjov's avatar Valentin Suhnjov

RIHAKB-130. Remove TokenStore

parent 76f0b8cb
package ee.eesti.riha.rest.auth;
/**
* The Interface TokenStore.
*/
public interface TokenStore {
/**
* Adds the token.
*
* @param token the token
* @param authInfo the auth info
*/
void addToken(String token, AuthInfo authInfo);
/**
* Return personCode corresponding to token or null if token does not exist.
*
* @param token the token
* @return the auth info
*/
AuthInfo tokenExists(String token);
/**
* Clear.
*/
void clear();
}
package ee.eesti.riha.rest.auth;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import ee.eesti.riha.rest.logic.Finals;
import ee.eesti.riha.rest.logic.util.StringHelper;
import ee.eesti.riha.rest.util.PropsReader;
// TODO: Auto-generated Javadoc
/**
* The Class TokenStoreImpl.
*/
@Component
public class TokenStoreImpl implements TokenStore {
// key token
private static Map<String, AuthInfo> tokenStorage = new HashMap<>();
// private static AuthInfo testAuthInfo = new AuthInfo("TEST_ISIKUKOOD", "TEST_ASUTUS", "TEST_ROLL");
private static AuthInfo testAuthInfo = new AuthInfo("TEST_ISIKUKOOD", "TEST_ASUTUS", "ROLL_RIHA_ADMINISTRAATOR");
private static boolean isTest = false;
private static final int NUM_OF_TIMEOUT_MAPS = 3;
// 3 maps: 1 to be deleted, 1 buffer, 1 where to put new ones
private static List<Map<String, String>> timeOutStorage = new ArrayList<>(NUM_OF_TIMEOUT_MAPS);
// public static final long TIME_OUT_IN_MS = 3600 * 1000L;
public static final long TIME_OUT_IN_MS = Long.valueOf(PropsReader.get("TIME_OUT_IN_MS"));
private static final int MAX_INDEX = 2;
private static long timeOutInMS = TIME_OUT_IN_MS;
private static int saveIndex = 0;
private static int counter = 0;
private static Date startNew = new Date();
private static final Logger LOG = LoggerFactory.getLogger(TokenStoreImpl.class);
/**
* Next.
*
* @param x the x
* @return the int
*/
public static int next(int x) {
if (x + 1 > MAX_INDEX) {
return 0;
} else {
return x + 1;
}
}
/**
* Previous.
*
* @param x the x
* @return the int
*/
public static int previous(int x) {
if (x - 1 < 0) {
return MAX_INDEX;
} else {
return x - 1;
}
}
static {
timeOutStorage.add(new HashMap<String, String>());
timeOutStorage.add(new HashMap<String, String>());
timeOutStorage.add(new HashMap<String, String>());
}
// LOGIC
// 1. token comes in
// 2. save token in tokenStorage
// 3. save token in timeOutStorage.get(saveIndex)
// 4. if timeout amount of time has passed then saveindex++
// 5. if timeout passes 2nd time then saveIndex++
// and empty timeOutStorage(saveIndex.previous.prevuois)
// 6. after that every timeout one will be emptied
// 7. if tokenExists called then save timeOut in new, delete in old
// 8. during emptying corresponding entries must be deleted in tokenStorage
// 9. clear clears all
/**
* List put and remove old.
*
* @param token the token
*/
private static void listPutAndRemoveOld(String token) {
String existing = timeOutStorage.get(saveIndex).put(token, token);
String removed = timeOutStorage.get(previous(saveIndex)).remove(token);
LOG.info("EXISTING: " + existing);
LOG.info("REMOVED: " + removed);
}
/**
* List get and update.
*
* @param token the token
* @return true, if successful
*/
private static boolean listGetAndUpdate(String token) {
boolean exists = false;
if (timeOutStorage.get(saveIndex).get(token) != null) {
exists = true;
} else {
if (timeOutStorage.get(previous(saveIndex)).get(token) != null) {
listPutAndRemoveOld(token);
exists = true;
}
}
return exists;
}
/**
* Delete old.
*
* @param deleteIndex the delete index
*/
private static void deleteOld(int deleteIndex) {
LOG.info("DELETEING ALL in " + deleteIndex + " : " + timeOutStorage.get(deleteIndex));
for (String token : timeOutStorage.get(deleteIndex).keySet()) {
getTokenStorage().remove(token);
}
timeOutStorage.get(deleteIndex).clear();
}
/*
* (non-Javadoc)
*
* @see ee.eesti.riha.rest.auth.TokenStore#addToken(java.lang.String, ee.eesti.riha.rest.auth.AuthInfo)
*/
@Override
public void addToken(String token, AuthInfo authInfo) {
Date current = new Date();
if (current.getTime() > startNew.getTime() + timeOutInMS) {
saveIndex = next(saveIndex);
counter++;
startNew = current;
if (counter >= 2) {
deleteOld(previous(previous(saveIndex)));
}
}
getTokenStorage().put(token, authInfo);
LOG.info("ADD TOKEN CALLED: " + token);
listPutAndRemoveOld(token);
LOG.info("AFTER ADD ");
printTimeoutStorage();
}
/*
* (non-Javadoc)
*
* @see ee.eesti.riha.rest.auth.TokenStore#tokenExists(java.lang.String)
*/
@Override
public AuthInfo tokenExists(String token) {
// to turn off token validation for tests
if (isTest) {
LOG.info("TOKEN EXISTS TEST CALLED: " + token);
return testAuthInfo;
}
if (Finals.IS_TEST && StringHelper.areEqual(token, Finals.TEST_TOKEN)) {
AuthInfo authInfo = getTokenStorage().get(token);
if (authInfo != null) {
return authInfo;
}
return testAuthInfo;
}
LOG.info("TOKEN EXISTS CALLED: " + token);
// remove if too old
if (!listGetAndUpdate(token)) {
getTokenStorage().remove(token);
}
return getTokenStorage().get(token);
}
/*
* (non-Javadoc)
*
* @see ee.eesti.riha.rest.auth.TokenStore#clear()
*/
@Override
public void clear() {
LOG.info("CLEAR TOKEN CALLED");
getTokenStorage().clear();
for (Map<String, String> map : timeOutStorage) {
map.clear();
}
counter = 0;
saveIndex = 0;
startNew = new Date();
LOG.info("" + getTokenStorage());
LOG.info("" + getTimeOutStorage());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TokenStoreImpl:: " + getTokenStorage();
}
/**
* Prints the timeout storage.
*/
public void printTimeoutStorage() {
LOG.info("TokenStore.tos :: " + timeOutStorage);
}
/**
* Checks if is test.
*
* @return true, if is test
*/
public static boolean isTest() {
return isTest;
}
/**
* Sets the test.
*
* @param aIsTest the new test
*/
public static void setTest(boolean aIsTest) {
TokenStoreImpl.isTest = aIsTest;
}
/**
* Gets the time out storage.
*
* @return the time out storage
*/
public static List<Map<String, String>> getTimeOutStorage() {
return timeOutStorage;
}
/**
* Gets the token storage.
*
* @return the token storage
*/
public static Map<String, AuthInfo> getTokenStorage() {
return tokenStorage;
}
/**
* Gets the time out in ms.
*
* @return the time out in ms
*/
public static long getTimeOutInMS() {
return timeOutInMS;
}
/**
* Sets the time out in ms.
*
* @param aTimeOutInMS the new time out in ms
*/
public static void setTimeOutInMS(long aTimeOutInMS) {
TokenStoreImpl.timeOutInMS = aTimeOutInMS;
}
}
package ee.eesti.riha.rest.logic;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ee.eesti.riha.rest.auth.AuthInfo;
import ee.eesti.riha.rest.auth.TokenStore;
import ee.eesti.riha.rest.error.ErrorCodes;
import ee.eesti.riha.rest.error.RihaRestError;
import ee.eesti.riha.rest.error.RihaRestException;
// TODO: Auto-generated Javadoc
/**
* The Class TokenValidator.
*/
public final class TokenValidator {
private static final Logger LOG = LoggerFactory.getLogger(TokenValidator.class);
private TokenValidator() {
}
/**
* Gets the token.
*
* @param httpHeaders the http headers
* @return the token
*/
public static String getToken(HttpHeaders httpHeaders) {
return httpHeaders.getHeaderString(Finals.X_AUTH_TOKEN);
}
/**
* Return true if token is valid, else throw exception.
*
* @param token the token
* @return true, if is token ok
* @throws RihaRestException the riha rest exception
*/
public static boolean isTokenOk(String token) throws RihaRestException {
if (!tokenNotEmpty(token)) {
RihaRestError error = new RihaRestError();
error.setErrcode(ErrorCodes.NO_AUTH_TOKEN_PROVIDED);
error.setErrmsg(ErrorCodes.NO_AUTH_TOKEN_PROVIDED_MSG);
// LOG.info(error);
throw new RihaRestException(error);
}
if (!isTokenValid(token)) {
RihaRestError error = new RihaRestError();
error.setErrcode(ErrorCodes.AUTH_TOKEN_INVALID);
error.setErrmsg(ErrorCodes.AUTH_TOKEN_INVALID_MSG);
// LOG.info(error);
throw new RihaRestException(error);
}
return true;
}
/**
* Return personCode if token is valid, else throw exception.
*
* @param token the token
* @param tokenStore the token store
* @return the auth info
* @throws RihaRestException the riha rest exception
*/
public static AuthInfo isTokenOk(String token, TokenStore tokenStore) throws RihaRestException {
// throws error if not ok
isTokenOk(token);
AuthInfo user = tokenStore.tokenExists(token);
if (user == null) {
RihaRestError error = new RihaRestError();
error.setErrcode(ErrorCodes.AUTH_TOKEN_INVALID);
error.setErrmsg(ErrorCodes.AUTH_TOKEN_INVALID_MSG);
throw new RihaRestException(error);
}
return user;
}
/**
* Checks if is token valid.
*
* @param token the token
* @return true, if is token valid
*/
private static boolean isTokenValid(String token) {
LOG.info(token);
return true;
}
/**
* Token not empty.
*
* @param token the token
* @return true, if successful
*/
private static boolean tokenNotEmpty(String token) {
if (StringUtils.isNotEmpty(token)) {
return true;
}
return false;
}
}
......@@ -3,20 +3,13 @@ package ee.eesti.riha.rest.service.impl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ee.eesti.riha.rest.auth.AuthInfo;
import ee.eesti.riha.rest.auth.TokenStore;
import ee.eesti.riha.rest.error.RihaRestError;
import ee.eesti.riha.rest.error.RihaRestException;
import ee.eesti.riha.rest.logic.ServiceLogic;
import ee.eesti.riha.rest.logic.TokenValidator;
import ee.eesti.riha.rest.service.ApiClassicService;
// TODO: Auto-generated Javadoc
......@@ -35,9 +28,6 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
@Context
HttpHeaders httpHeaders;
@Autowired
TokenStore tokenStore;
private static final Logger LOG = LoggerFactory.getLogger(ApiClassicServiceImpl.class);
/*
......@@ -59,7 +49,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.getMany(tableName, limit, offset, filter,
sort, fields);
}
......@@ -82,7 +72,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.getById(tableName, id, fields);
}
}).doIfHeadersOk();
......@@ -104,7 +94,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.getResourceById(id);
}
}).doIfHeadersOk();
......@@ -123,7 +113,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.create(json, tableName);
}
}).doIfHeadersOk();
......@@ -142,7 +132,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.update(json, tableName, id);
}
}).doIfHeadersOk();
......@@ -161,7 +151,7 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
return (new Command() {
@Override
public Response commandMethod(Object user) {
public Response commandMethod() {
return serviceLogic.delete(tableName, id);
}
}).doIfHeadersOk();
......@@ -179,34 +169,15 @@ public class ApiClassicServiceImpl<T, K> implements ApiClassicService {
* @return the response
*/
public Response doIfHeadersOk() {
try {
String token = TokenValidator.getToken(httpHeaders);
if (!StringUtils.isEmpty(token)) {
// if (TokenValidator.areHeadersOk(httpHeaders)) {
// return commandMethod(TokenValidator.isTokenOk(
// TokenValidator.getToken(httpHeaders), getAuthService()));
return commandMethod(TokenValidator.isTokenOk(TokenValidator.getToken(httpHeaders), tokenStore));
} else {
return commandMethod(AuthInfo.DEFAULT);
}
// areHeadersOK must return true or throw exception
// throw new RuntimeException("This should never happen!");
} catch (RihaRestException e) {
RihaRestError error = (RihaRestError) e.getError();
// don't show stacktrace
// error.setErrtrace(Arrays.toString(e.getStackTrace()));
return Response.status(Status.BAD_REQUEST).entity(error).build();
}
return commandMethod();
}
/**
* Abstract method which should call ServiceLogic method.
*
* @param user the user
* @return the response
*/
public abstract Response commandMethod(Object user);
public abstract Response commandMethod();
}
}
......@@ -10,7 +10,6 @@ import org.springframework.stereotype.Component;
import com.google.gson.JsonObject;
import ee.eesti.riha.rest.auth.TokenStore;
import ee.eesti.riha.rest.error.RihaRestException;
import ee.eesti.riha.rest.logic.Finals;
import ee.eesti.riha.rest.logic.ImportLogic;
......@@ -24,9 +23,6 @@ public class ApiImportServiceImpl implements ApiImportService {
@Autowired
ImportLogic importLogic;
@Autowired
TokenStore tokenStore;
@Override
public Response doImport(String json, String token) {
System.out.println("Import");
......
package ee.eesti.riha.rest;
import org.springframework.beans.factory.annotation.Autowired;
import ee.eesti.riha.rest.auth.AuthInfo;
import ee.eesti.riha.rest.auth.TokenStore;
import ee.eesti.riha.rest.logic.Finals;
/**
* Helper factory to provide {@link AuthInfo} objects for unit testing.
*
* @author A
*
*/
public class AuthInfoTestTokenFactory {
@Autowired
TokenStore tokenStore;
public AuthInfo getTestToken() {
return tokenStore.tokenExists(Finals.TEST_TOKEN);
}
}
package ee.eesti.riha.rest.auth;
import static org.junit.Assert.*;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
public class TestTokenStoreImpl {
TokenStoreImpl tokenStore = new TokenStoreImpl();
String token = "asdasd";
String personCode = "123123";
AuthInfo testAuthInfo = new AuthInfo(personCode, null, null, null);
static final long TEST_TIME_OUT_IN_MS = 200L;
long sleep = TEST_TIME_OUT_IN_MS + 10;
List<Map<String, String>> timeOutStorage = TokenStoreImpl.getTimeOutStorage();
@Before
public void beforeTest() {
tokenStore.clear();
TokenStoreImpl.setTest(false);
TokenStoreImpl.setTimeOutInMS(TEST_TIME_OUT_IN_MS);
}
@Test
public void testAddToken() {
tokenStore.addToken(token, testAuthInfo);
AuthInfo authInfo = tokenStore.tokenExists(token);
assertNotNull(authInfo);
assertNull(authInfo.getOrg_code());
assertEquals(personCode, authInfo.getUser_code());
}
@Test
public void testTokenExists_withTest() {
TokenStoreImpl.setTest(true);
tokenStore.addToken(token, testAuthInfo);
AuthInfo authInfo = tokenStore.tokenExists(token);
assertNotNull(authInfo);
// TokenStoreIMpl testAuthInfo is returned
assertNotNull(authInfo.getOrg_code());
assertNotEquals(personCode, authInfo.getUser_code());
}
@Test
public void testTokenExists_withTimeout() throws InterruptedException {
System.out.println("BEFOER FAIL: " + TokenStoreImpl.getTokenStorage());
tokenStore.addToken(token, testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 0, 0);
Thread.sleep(sleep);
tokenStore.addToken(token + "xxx", testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 1, 0);
Thread.sleep(sleep);
tokenStore.addToken(token + "yyy", testAuthInfo);
assertStorageSizes(timeOutStorage, 0, 1, 1);
Thread.sleep(sleep);
tokenStore.addToken(token + "zzz", testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 0, 1);
Thread.sleep(sleep);
tokenStore.addToken(token + "ppp", testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 1, 0);
Thread.sleep(sleep);
tokenStore.addToken(token + "SSS", testAuthInfo);
assertStorageSizes(timeOutStorage, 0, 1, 1);
tokenStore.printTimeoutStorage();
assertNull(tokenStore.tokenExists(token));
assertNotNull(tokenStore.tokenExists(token + "ppp"));
assertNotNull(tokenStore.tokenExists(token + "SSS"));
assertEquals(2, TokenStoreImpl.getTokenStorage().size());
}
@Test
public void testTokenExists_withTimeout_useMultipleTimes() throws InterruptedException {
tokenStore.addToken(token, testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 0, 0);
Thread.sleep(sleep);
tokenStore.addToken(token + "xxx", testAuthInfo);
assertStorageSizes(timeOutStorage, 1, 1, 0);
Thread.sleep(sleep);
assertNotNull(tokenStore.tokenExists(token));
tokenStore.addToken(token + "yyy", testAuthInfo);
assertStorageSizes(timeOutStorage, 0, 2, 1);
Thread.sleep(sleep);
assertNotNull(tokenStore.tokenExists(token));
assertNotNull(tokenStore.tokenExists(token + "xxx"));