package io.fathom.cloud.identity.api.os.resources;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.PATCH;
import io.fathom.cloud.identity.api.os.model.Projects;
import io.fathom.cloud.identity.api.os.model.User;
import io.fathom.cloud.identity.api.os.model.Users;
import io.fathom.cloud.identity.api.os.model.WrappedUser;
import io.fathom.cloud.identity.model.AuthenticatedUser;
import io.fathom.cloud.identity.secrets.Secrets;
import io.fathom.cloud.identity.services.IdentityService.UserCreationData;
import io.fathom.cloud.identity.state.AuthRepository;
import io.fathom.cloud.protobuf.IdentityModel.DomainData;
import io.fathom.cloud.protobuf.IdentityModel.ProjectData;
import io.fathom.cloud.protobuf.IdentityModel.ProjectRoles;
import io.fathom.cloud.protobuf.IdentityModel.UserData;
import io.fathom.cloud.server.auth.Auth;
import io.fathom.cloud.state.NumberedItemCollection;
import javax.inject.Inject;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.inject.persist.Transactional;
@Path("/openstack/identity/v3/users")
@Transactional
@Produces({ "application/json" })
public class UsersResource extends IdentityResourceBase {
private static final Logger log = LoggerFactory.getLogger(UsersResource.class);
// Should use identity service instead
@Deprecated
@Inject
AuthRepository authRepository;
@GET
@Produces({ JSON })
public Users listUsers() throws CloudException {
Auth.Domain domain = findDomainWithAdminRole();
if (domain == null) {
throw new WebApplicationException(Status.FORBIDDEN);
}
Users response = new Users();
response.users = Lists.newArrayList();
for (UserData data : authRepository.getUsers().list()) {
if (data.getDomainId() != domain.getId()) {
continue;
}
User user = toModel(data);
response.users.add(user);
}
return response;
}
@PATCH
@Path("{id}")
@Produces({ JSON })
public WrappedUser patchUser(@PathParam("id") long id, WrappedUser wrapped) throws CloudException {
AuthenticatedUser user = getAuthenticatedUser();
NumberedItemCollection<UserData> users = authRepository.getUsers();
// UserData user = users.find(id);
// if (user == null) {
// throw new WebApplicationException(Status.NOT_FOUND);
// }
if (id != user.getUserId()) {
// requireAdmin();
// Tricky to change password
// TODO: Support changing non-encrypted fields?
throw new UnsupportedOperationException();
}
User req = wrapped.user;
UserData updated;
{
UserData.Builder b = UserData.newBuilder(user.getUserData());
if (!Strings.isNullOrEmpty(req.description)) {
b.setDescription(req.description);
}
if (req.enabled != null) {
b.setEnabled(req.enabled);
}
if (req.defaultProjectId != null) {
b.setDefaultProjectId(Long.valueOf(req.defaultProjectId));
}
if (!Strings.isNullOrEmpty(req.password)) {
Secrets.setPassword(b.getSecretStoreBuilder(), req.password, user.getKeys());
// DomainData domain =
// authRepository.getDomains().find(user.getDomainId());
// NamedItemCollection<CredentialData> usernames =
// authRepository.getUsernames(domain);
//
// CredentialData credential = usernames.find(user.getName());
//
// if (credential.getUserId() != user.getId()) {
// throw new IllegalStateException();
// }
//
// CredentialData.Builder b =
// CredentialData.newBuilder(credential);
//
// PasswordHashData passwordHash = hasher.hash(req.password);
// b.setPasswordHash(passwordHash);
//
// usernames.update(b);
}
updated = users.update(b);
}
WrappedUser response = new WrappedUser();
response.user = toModel(updated);
return response;
}
@POST
@Produces({ JSON })
public WrappedUser createUser(WrappedUser wrappedUser) throws CloudException {
Auth.Domain domain = findDomainWithAdminRole();
if (domain == null) {
// TODO: Allow foreign domain creation?
throw new WebApplicationException(Status.FORBIDDEN);
}
User req = wrappedUser.user;
DomainData domainData = authRepository.getDomains().find(domain.getId());
if (domainData == null) {
throw new IllegalStateException();
}
if (Strings.isNullOrEmpty(req.domainId)) {
// domain = getDomainFromToken();
} else {
if (Long.valueOf(req.domainId) != domainData.getId()) {
// TODO: Allow this?
throw new UnsupportedOperationException();
}
// domain = getDomain(Long.valueOf(req.domainId));
}
ProjectData project = getProject(Long.valueOf(req.defaultProjectId));
UserData.Builder b = UserData.newBuilder();
if (!Strings.isNullOrEmpty(req.description)) {
b.setDescription(req.description);
}
b.setName(req.name);
b.setDomainId(domain.getId());
if (req.enabled != null) {
b.setEnabled(req.enabled);
} else {
b.setEnabled(true);
}
if (project != null) {
b.setDefaultProjectId(project.getId());
}
b.setEmail(req.email);
UserData user = identityService.createUser(new UserCreationData(domainData, b, req.password));
WrappedUser response = new WrappedUser();
response.user = toModel(user);
return response;
}
@GET
@Path("{id}")
@Produces({ JSON })
public WrappedUser getUserDetails(@PathParam("id") long id) throws CloudException {
UserData user = getUser(id);
WrappedUser response = new WrappedUser();
response.user = toModel(user);
return response;
}
@DELETE
@Path("{id}")
public Response deleteUser(@PathParam("id") long id) throws Exception {
UserData user = getUser(id);
if (user.getId() == getUser().getId()) {
// Prevent users from shooting themselves in the foot
throw new IllegalArgumentException();
}
identityService.deleteUser(user);
ResponseBuilder response = Response.noContent();
return response.build();
}
@GET
@Path("{id}/projects")
@Produces({ JSON })
public Projects getUserProjects(@PathParam("id") long id) throws CloudException {
UserData user = getUser(id);
Projects response = new Projects();
response.projects = Lists.newArrayList();
for (ProjectRoles projectRole : user.getProjectRolesList()) {
long projectId = projectRole.getProject();
ProjectData project = authRepository.getProjects().find(projectId);
if (project == null) {
log.warn("Cannot find project {}", projectId);
continue;
}
response.projects.add(toModel(project));
}
return response;
}
private User toModel(UserData data) {
User user = new User();
user.id = "" + data.getId();
user.name = data.getName();
if (data.hasEmail()) {
user.email = data.getEmail();
} else {
user.email = user.name;
}
if (data.hasDescription()) {
user.description = data.getDescription();
}
if (data.hasEnabled()) {
user.enabled = data.getEnabled();
} else {
user.enabled = true;
}
user.domainId = "" + data.getDomainId();
if (data.hasDefaultProjectId()) {
user.defaultProjectId = "" + data.getDefaultProjectId();
}
return user;
}
}