TokenRepositoryInMemory.java
/*
* Copyright 2015 Aroma Tech.
*
* Licensed 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 tech.aroma.banana.authentication.service.data;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.aroma.banana.thrift.exceptions.InvalidTokenException;
import tech.sirwellington.alchemy.annotations.designs.patterns.StrategyPattern;
import static java.time.Instant.now;
import static tech.aroma.banana.authentication.service.AuthenticationAssertions.tokenInRepository;
import static tech.sirwellington.alchemy.annotations.designs.patterns.StrategyPattern.Role.CONCRETE_BEHAVIOR;
import static tech.sirwellington.alchemy.arguments.Arguments.checkThat;
import static tech.sirwellington.alchemy.arguments.assertions.Assertions.notNull;
import static tech.sirwellington.alchemy.arguments.assertions.StringAssertions.nonEmptyString;
/**
*
* @author SirWellington
*/
@StrategyPattern(role = CONCRETE_BEHAVIOR)
final class TokenRepositoryInMemory implements TokenRepository
{
private final static Logger LOG = LoggerFactory.getLogger(TokenRepositoryInMemory.class);
private final Map<String, Token> tokens = Maps.newConcurrentMap();
private final Map<String, List<Token>> tokensByOwner = Maps.newConcurrentMap();
private final Map<String, Instant> tokenExpiration = Maps.newConcurrentMap();
@Override
public boolean doesTokenExist(String tokenId) throws IllegalArgumentException
{
checkThat(tokenId).is(nonEmptyString());
if (!tokens.containsKey(tokenId))
{
return false;
}
if (isExpired(tokenId))
{
LOG.debug("Token is now expired. Removing it. {}", tokenId);
removeToken(tokenId);
return false;
}
return true;
}
@Override
public Token getToken(String tokenId) throws TException
{
checkThat(tokenId)
.is(nonEmptyString())
.throwing(InvalidTokenException.class)
.is(tokenInRepository(this));
if (isExpired(tokenId))
{
removeToken(tokenId);
}
return tokens.get(tokenId);
}
@Override
public void saveToken(Token token) throws TException
{
checkThat(token)
.usingMessage("token is null")
.is(notNull());
checkThat(token.getTokenType())
.usingMessage("tokenType is required")
.is(notNull());
Instant expiration = token.getTimeOfExpiration();
checkThat(expiration)
.usingMessage("token is missing an expiration date.")
.is(notNull());
String tokenId = token.getTokenId();
String ownerId = token.getOwnerId();
checkThat(tokenId, ownerId)
.usingMessage("tokenId and ownerId must be present in Token")
.are(nonEmptyString());
tokens.put(tokenId, token);
tokenExpiration.put(tokenId, expiration);
List<Token> ownerTokens = tokensByOwner.getOrDefault(ownerId, Lists.newArrayList());
ownerTokens.add(token);
tokensByOwner.put(ownerId, ownerTokens);
}
@Override
public List<Token> getTokensBelongingTo(String ownerId) throws IllegalArgumentException
{
checkThat(ownerId).is(nonEmptyString());
List<Token> allTokens = tokensByOwner.getOrDefault(ownerId, Lists.newArrayList());
//Sending a separate list ensures we send a defensive copy.
List<Token> results = Lists.newArrayList();
for (Token token : allTokens)
{
String tokenId = token.getTokenId();
if (isExpired(tokenId))
{
removeToken(tokenId);
continue;
}
results.add(token);
}
return results;
}
@Override
public void deleteToken(String tokenId) throws IllegalArgumentException
{
checkThat(tokenId).is(nonEmptyString());
removeToken(tokenId);
}
private boolean isExpired(String tokenId)
{
Instant now = now();
Instant expiration = tokenExpiration.get(tokenId);
if (expiration == null)
{
return false;
}
return expiration.isBefore(now);
}
private void removeToken(String tokenId)
{
tokenExpiration.remove(tokenId);
Token token = tokens.remove(tokenId);
//Token never existed
if (token == null)
{
return;
}
String ownerId = token.getOwnerId();
List<Token> tokens = tokensByOwner.get(ownerId);
if (tokens != null)
{
tokens.remove(token);
}
}
}