package de.passau.uni.sec.compose.id.core.service;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import de.passau.uni.sec.compose.id.common.exception.IdManagementException;
import de.passau.uni.sec.compose.id.common.exception.IdManagementException.Level;
import de.passau.uni.sec.compose.id.core.domain.ComposeComponentPrincipal;
import de.passau.uni.sec.compose.id.core.domain.ComposeUserPrincipal;
import de.passau.uni.sec.compose.id.core.domain.IPrincipal;
import de.passau.uni.sec.compose.id.core.event.CreateUserEvent;
import de.passau.uni.sec.compose.id.core.event.Event;
import de.passau.uni.sec.compose.id.core.event.GetUserEvent;
import de.passau.uni.sec.compose.id.core.event.DetailsIdEvent;
import de.passau.uni.sec.compose.id.core.event.UpdateUserEvent;
import de.passau.uni.sec.compose.id.core.persistence.entities.Global;
import de.passau.uni.sec.compose.id.core.persistence.entities.IEntity;
import de.passau.uni.sec.compose.id.core.persistence.entities.ServiceInstance;
import de.passau.uni.sec.compose.id.core.persistence.entities.User;
import de.passau.uni.sec.compose.id.core.persistence.repository.UniqueRepository;
import de.passau.uni.sec.compose.id.core.persistence.repository.UserRepository;
import de.passau.uni.sec.compose.id.core.service.reputation.ReputationManager;
import de.passau.uni.sec.compose.id.core.service.security.Authorization;
import de.passau.uni.sec.compose.id.core.service.security.RestAuthentication;
import de.passau.uni.sec.compose.id.core.service.security.UsersAuthzAndAuthClient;
import de.passau.uni.sec.compose.id.core.service.security.uaa.UAAUserRequest;
import de.passau.uni.sec.compose.id.core.service.security.uaa.UAAUserRequestName;
import de.passau.uni.sec.compose.id.rest.messages.EntityResponseMessage;
import de.passau.uni.sec.compose.id.rest.messages.UserResponseMessage;
@Service
@PropertySource("classpath:anonymousUser.properties")
public class UserService extends AbstractSecureEntityBasicEntityService implements EntityService
{
private static Logger LOG = LoggerFactory.getLogger(UserService.class);
/**
* Should be passed to ComposeRepository to manage exceptions... never access it directly
*/
@Autowired
UserRepository userRepository;
@Autowired
UsersAuthzAndAuthClient uaa;
@Autowired
Authorization authz;
@Autowired
ReputationManager rep;
@Autowired
RestAuthentication auth;
@Autowired
Random random;
@Autowired
UniqueValidation check;
@Autowired
private Environment env;
@Autowired
UniqueRepository uniqueRepository;
/**
* Put an anonymous user in local database.
* @throws IdManagementException
*/
@PostConstruct
public void initAnonuser() throws IdManagementException {
// create an anonymous user in the local database
User u = new User();
u.setId(env.getRequiredProperty("anonid"));
u.setReputation(rep.getReputationValueforNewUser());
u.setUsername(env.getRequiredProperty("anonusername"));
u.setReputation(0);
// u.setLastModified(new Date(System.currentTimeMillis()));
u.setRandom_auth_token(env.getRequiredProperty("anontoken"));
u = userRepository.save(u);
check.insertUnique(env.getRequiredProperty("anonid"), check.USER);
}
@Override
protected EntityResponseMessage postACCreateEntity(Event event)
throws IdManagementException {
CreateUserEvent create = ((CreateUserEvent) event);
// Build the UAA request for creating a user.
UAAUserRequest uaaData = new UAAUserRequest();
uaaData.setUsername(create.getUserMessage().getUsername());
uaaData.setPassword(create.getUserMessage().getPassword());
uaaData.addEmail(create.getUserMessage().getUsername()+"@compose.com");
UAAUserRequestName name = new UAAUserRequestName();
name.setFamilyName("compose");
name.setGivenName(create.getUserMessage().getUsername());
name.setFormatted(" ");
uaaData.setName(name);
//create user in the UAA
Map<String,Object> UAAResponse = uaa.createUser(uaaData);
String id = (String) UAAResponse.get("id");
if(id == null)
throw new IdManagementException("Internal communication error",null,LOG,"UAA Creation of user doesn't have an id"+UAAResponse,Level.ERROR,500);
//create user in the local database
User u = new User();
u.setId(id);
u.setReputation(rep.getReputationValueforNewUser());
u.setUsername(create.getUserMessage().getUsername());
//u.setLastModified(new Date(System.currentTimeMillis()));
u.setRandom_auth_token(random.getRandomToken());
u = userRepository.save(u);
check.insertUnique(id, check.USER);
UserResponseMessage res = new UserResponseMessage(u);
return res;
}
@Override
protected EntityResponseMessage postACGetEntity(Event event)
throws IdManagementException {
User u = null;
if(event instanceof GetUserEvent)
{
GetUserEvent get = ((GetUserEvent) event);
u = userRepository.getOne(get.getId());
}
else{
ComposeUserPrincipal comp = auth.getComposeUser(event.getPrincipals());
u = userRepository.getOne(comp.getOpenId().getUser_id());
}
UserResponseMessage res = new UserResponseMessage(u);
try{
authz.authorizeIfOwnerOrComponent(event.getPrincipals(), u);
res.setRandom_auth_token(u.getRandom_auth_token());
}catch(IdManagementException ex)
{
//Its ok, he is not asking data about himself...
}
return res;
}
@Override
protected EntityResponseMessage postACUpdateEntity(DetailsIdEvent event, IEntity previous)
throws IdManagementException {
UpdateUserEvent update = ((UpdateUserEvent) event);
User u = new User();
UserResponseMessage message = new UserResponseMessage(u);
//String epoch = update.getLastModifiedKnown();
//TODO verify that the last modification of the user coincides with the timestamp in the event.
// 403 Forbidden, 304 Not modified, or 409 not modified (conflict),
return message;
}
@Override
protected void verifyAccessControlCreateEntity(Event event)
throws IdManagementException {
boolean ok = false;
Collection<IPrincipal> principals = event.getPrincipals();
for(IPrincipal p: principals)
{
if(p instanceof ComposeComponentPrincipal)
{
//TODO Add additional AC rules if required
//if(((ComposeComponentPrincipal)p).getComposeComponentName().equals("sdk"))
ok = true;
LOG.debug("Compose Principal "+((ComposeComponentPrincipal)p).getComposeComponentName()+" executing User creation: ");
}
}
if(!ok)
throw new IdManagementException("Not sufficient permissions for the action requred ",null, LOG,"The entities authenticated for the request do not have sufficient permissions to execute it, principals "+RestAuthentication.getBasicInfoPrincipals(principals),Level.DEBUG, 403);
}
@Override
protected void verifyAccessControlUpdateEntity(DetailsIdEvent event)
throws IdManagementException {
// TODO Ensure that it is the same user
}
@Override
protected Logger getLogger()
{
return LOG;
}
@Override
protected IEntity getEntityById(String entityId) {
return userRepository.getOne(entityId);
}
@Override
protected void postACDeleteEntity(DetailsIdEvent event)
throws IdManagementException {
User sc = userRepository.getOne(event.getEntityId());
//the user repository will throw exception if the user still has any associations (groups...etc), so we do it first
userRepository.delete(sc);
Global entity = uniqueRepository.findOne(event.getEntityId());
uniqueRepository.delete(entity);
uaa.deleteUser(sc.getId());
}
@Override
protected void verifyAccessControlDeleteEntity(DetailsIdEvent event)
throws IdManagementException {
User sc = userRepository.getOne(event.getEntityId());
authz.authorizeIfOwnerOrComponent(event.getPrincipals(), sc);
}
}