package de.passau.uni.sec.compose.id.core.service;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.ComposeUserPrincipal;
import de.passau.uni.sec.compose.id.core.domain.IPrincipal;
import de.passau.uni.sec.compose.id.core.event.CreateGroupEvent;
import de.passau.uni.sec.compose.id.core.event.Event;
import de.passau.uni.sec.compose.id.core.event.GetGroupEvent;
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.Application;
import de.passau.uni.sec.compose.id.core.persistence.entities.Group;
import de.passau.uni.sec.compose.id.core.persistence.entities.IEntity;
import de.passau.uni.sec.compose.id.core.persistence.entities.Membership;
import de.passau.uni.sec.compose.id.core.persistence.entities.Role;
import de.passau.uni.sec.compose.id.core.persistence.entities.User;
import de.passau.uni.sec.compose.id.core.persistence.repository.GroupRepository;
import de.passau.uni.sec.compose.id.core.persistence.repository.MembershipRepository;
import de.passau.uni.sec.compose.id.core.persistence.repository.RoleRepository;
import de.passau.uni.sec.compose.id.core.persistence.repository.UserRepository;
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.rest.messages.EntityResponseMessage;
import de.passau.uni.sec.compose.id.rest.messages.GroupCreateMessage;
import de.passau.uni.sec.compose.id.rest.messages.GroupResponseMessage;
import de.passau.uni.sec.compose.id.rest.messages.UserResponseMessage;
@Service
public class GroupService extends AbstractSecureEntityBasicEntityService implements EntityService
{
private static Logger LOG = LoggerFactory.getLogger(GroupService.class);
@Autowired
GroupRepository groupRepository;
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
RestAuthentication authentication;
@Autowired
Authorization authz;
@Autowired
MembershipRepository membershipRepository;
@Autowired
private CloudPublisher pub;
@Autowired
UpdateManager updater;
@Override
protected EntityResponseMessage postACCreateEntity(Event event)
throws IdManagementException {
//After this call we are sure there is a user, otherwise an exception would have been thrown
CreateGroupEvent group = (CreateGroupEvent) event;
User u = authentication.getUserFromEvent(event);
Collection<Group> userGroups = u.getGroups();
for(Group i: userGroups)
if(i.getName().equals(group.getMessage().getName()))
throw new IdManagementException("Entity already exists",null,LOG,"There is a group with the same name for the user already"+group.getLoggingDetails(),Level.DEBUG,409);
GroupCreateMessage message = group.getMessage();
Group g = new Group();
g.setId(UUID.randomUUID().toString());
g.setName(message.getName());
g.setOwner(u);
groupRepository.save(g);
//So that the user has memberships of ADMIN for the groups he owns
createGroupMembershipAdmin(g,u);
updater.handleUpdateForEntity(u.getId(),event.getPrincipals());
GroupResponseMessage res = new GroupResponseMessage(g);
return res;
}
private void createGroupMembershipAdmin(Group g, User u)
{
Role r = roleRepository.findOne(Role.ADMIN);
if(r!=null)
{
Membership memb = new Membership();
memb.setApprovedByGroupOwner(true);
memb.setApprovedByUser(true);
memb.setGroup(g);
memb.setId(UUID.randomUUID().toString());
memb.setRole(r);
memb.setUser(u);
membershipRepository.save(memb);
}
}
@Override
protected EntityResponseMessage postACGetEntity(Event event)
throws IdManagementException {
GetGroupEvent get = ((GetGroupEvent) event);
Group g = groupRepository.getOne(get.getId());
if(g == null)
throw new IdManagementException("Entity not found",null,LOG,"Entity not found, event :"+get.getLoggingDetails(),Level.DEBUG,404);
GroupResponseMessage res = new GroupResponseMessage(g);
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 Logger getLogger()
{
return LOG;
}
@Override
protected IEntity getEntityById(String entityId) {
return groupRepository.getOne(entityId);
}
@Override
protected void postACDeleteEntity(DetailsIdEvent event)
throws IdManagementException {
Group g = groupRepository.getOne(event.getEntityId());
List<Membership> memb = membershipRepository.findByGroup(g);
String userIdFromMembership = memb.get(0).getUser().getId();
User userFromEvent = authentication.getUserFromEvent(event);
if( memb.size() == 0 ||
(memb.size() == 1 && userFromEvent.getId().equals(userIdFromMembership))
)
{
membershipRepository.delete(memb.get(0));
groupRepository.delete(g);
updater.handleUpdateForEntity(userIdFromMembership,event.getPrincipals());
}
else
throw new IdManagementException("Conflict: group has memberships",null,LOG,"group has memberships: group id"+event.getEntityId(),Level.DEBUG,409);
}
@Override
protected void verifyAccessControlDeleteEntity(DetailsIdEvent event)
throws IdManagementException {
Group g = groupRepository.getOne(event.getEntityId());
authz.authorizeIfOwner(event.getPrincipals(), g);
}
}