package org.molgenis.security.token;
import org.apache.commons.lang3.time.DateUtils;
import org.molgenis.auth.Token;
import org.molgenis.auth.TokenFactory;
import org.molgenis.auth.User;
import org.molgenis.data.DataService;
import org.molgenis.security.core.runas.RunAsSystem;
import org.molgenis.security.core.token.TokenService;
import org.molgenis.security.core.token.UnknownTokenException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.molgenis.auth.TokenMetaData.TOKEN;
import static org.molgenis.auth.TokenMetaData.TOKEN_ATTR;
import static org.molgenis.auth.UserMetaData.USER;
import static org.molgenis.auth.UserMetaData.USERNAME;
/**
* TokensService implementation that uses the DataService
*/
public class DataServiceTokenService implements TokenService
{
private final TokenGenerator tokenGenerator;
private final DataService dataService;
private final UserDetailsService userDetailsService;
private final TokenFactory tokenFactory;
public DataServiceTokenService(TokenGenerator tokenGenerator, DataService dataService,
UserDetailsService userDetailsService, TokenFactory tokenFactory)
{
this.tokenGenerator = requireNonNull(tokenGenerator);
this.dataService = requireNonNull(dataService);
this.userDetailsService = requireNonNull(userDetailsService);
this.tokenFactory = requireNonNull(tokenFactory);
}
/**
* Find a user by a security token
*
* @param token security token
* @return the user or null if not found or token is expired
*/
@Override
@Transactional(readOnly = true)
@RunAsSystem
public UserDetails findUserByToken(String token) throws UnknownTokenException
{
Token molgenisToken = getMolgenisToken(token);
return userDetailsService.loadUserByUsername(molgenisToken.getUser().getUsername());
}
/**
* Generates a token and associates it with a user.
* <p>
* Token expires in 2 hours
*
* @param username username
* @param description token description
* @return token
*/
@Override
@Transactional
@RunAsSystem
public String generateAndStoreToken(String username, String description)
{
User user = dataService.query(USER, User.class).eq(USERNAME, username).findOne();
if (user == null)
{
throw new IllegalArgumentException(format("Unknown username [%s]", username));
}
String token = tokenGenerator.generateToken();
Token molgenisToken = tokenFactory.create();
molgenisToken.setUser(user);
molgenisToken.setToken(token);
molgenisToken.setDescription(description);
molgenisToken.setExpirationDate(DateUtils.addHours(new Date(), 2));
dataService.add(TOKEN, molgenisToken);
return token;
}
@Override
@Transactional
@RunAsSystem
public void removeToken(String token) throws UnknownTokenException
{
Token molgenisToken = getMolgenisToken(token);
dataService.delete(TOKEN, molgenisToken);
}
private Token getMolgenisToken(String token) throws UnknownTokenException
{
Token molgenisToken = dataService.query(TOKEN, Token.class).eq(TOKEN_ATTR, token).findOne();
if ((molgenisToken == null) || ((molgenisToken.getExpirationDate() != null) && new Date()
.after(molgenisToken.getExpirationDate())))
{
throw new UnknownTokenException("Invalid token");
}
return molgenisToken;
}
}