package io.fathom.cloud.identity.api.os.resources;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.ServiceType;
import io.fathom.cloud.identity.api.os.model.User;
import io.fathom.cloud.identity.api.os.model.v2.Access;
import io.fathom.cloud.identity.api.os.model.v2.Role;
import io.fathom.cloud.identity.api.os.model.v2.Tenant;
import io.fathom.cloud.identity.api.os.model.v2.V2AuthCredentials;
import io.fathom.cloud.identity.api.os.model.v2.V2AuthRequest;
import io.fathom.cloud.identity.api.os.model.v2.V2AuthResponse;
import io.fathom.cloud.identity.api.os.model.v2.V2Endpoint;
import io.fathom.cloud.identity.api.os.model.v2.V2Service;
import io.fathom.cloud.identity.api.os.model.v2.V2Token;
import io.fathom.cloud.identity.api.os.model.v3.Endpoint;
import io.fathom.cloud.identity.api.os.model.v3.Service;
import io.fathom.cloud.identity.model.AuthenticatedUser;
import io.fathom.cloud.protobuf.CloudCommons.TokenInfo;
import io.fathom.cloud.protobuf.IdentityModel.ProjectData;
import io.fathom.cloud.protobuf.IdentityModel.RoleData;
import io.fathom.cloud.server.auth.TokenAuth;
import io.fathom.cloud.server.resources.ClientCertificate;
import java.util.List;
import java.util.Map;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
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.common.collect.Maps;
import com.google.common.io.BaseEncoding;
import com.google.inject.persist.Transactional;
import com.google.protobuf.ByteString;
@Path("/openstack/identity/v2.0/tokens")
@Transactional
@Produces({ "application/json" })
public class V2TokensResource extends IdentityResourceBase {
private static final Logger log = LoggerFactory.getLogger(V2TokensResource.class);
@POST
public V2AuthResponse doTokensPost(V2AuthRequest request) throws CloudException {
V2AuthCredentials authRequest = request.authInfo;
if (authRequest == null) {
authRequest = new V2AuthCredentials();
}
boolean hasPasswordCredentials = false;
if (authRequest.passwordCredentials != null && !Strings.isNullOrEmpty(authRequest.passwordCredentials.username)) {
hasPasswordCredentials = true;
}
boolean hasChallengeResponse = false;
if (authRequest.challengeResponse != null && !Strings.isNullOrEmpty(authRequest.challengeResponse.challenge)) {
hasChallengeResponse = true;
}
ClientCertificate clientCertificate = getClientCertificate();
if (!hasPasswordCredentials) {
if (!hasChallengeResponse) {
if (clientCertificate != null) {
// Request for challenge
ByteString challenge = loginService.getChallenge(clientCertificate);
if (challenge != null) {
V2AuthResponse response = new V2AuthResponse();
response.challenge = BaseEncoding.base64().encode(challenge.toByteArray());
return response;
}
}
}
}
AuthenticatedUser authentication = null;
if (authRequest != null) {
authentication = loginService.authenticate(authRequest, clientCertificate);
}
if (authentication == null) {
throw new WebApplicationException(Status.UNAUTHORIZED);
}
V2AuthResponse response = new V2AuthResponse();
Access access = response.access = new Access();
V2Token token = access.token = new V2Token();
ProjectData project = authentication.getProject();
// We never pass domain; we can't build a domain token with V2
TokenInfo tokenInfo = loginService.buildTokenInfo(authentication);
token.expires = TokenAuth.getExpiration(tokenInfo);
token.id = tokenService.encodeToken(tokenInfo);
if (project != null) {
Tenant tenant = new Tenant();
tenant.id = "" + project.getId();
tenant.name = project.getName();
token.tenant = tenant;
}
if (project != null) {
List<Service> v3Services = loginService.buildServiceMap(getBaseUrl(), project);
access.services = toV2Services(project, v3Services);
}
User user = access.user = new User();
user.id = "" + authentication.getUserData().getId();
user.name = authentication.getUserData().getName();
if (authentication.getProjectRoleIds() != null) {
user.roles = Lists.newArrayList();
for (long roleId : authentication.getProjectRoleIds()) {
RoleData role = identityService.findRole(roleId);
if (role == null) {
throw new IllegalStateException();
}
Role model = toModel(project, role);
user.roles.add(model);
}
}
log.info("Returning auth: {}", response);
return response;
}
private List<V2Service> toV2Services(ProjectData project, List<Service> v3Services) {
List<V2Service> v2Services = Lists.newArrayList();
for (Service v3 : v3Services) {
V2Service v2 = new V2Service();
v2Services.add(v2);
v2.name = v3.name;
v2.type = v3.type;
v2.endpoints = toV2Endpoints(project, v3.endpoints);
// TODO: What happened to version in V3??
if (v2.type.equals(ServiceType.COMPUTE.getType())) {
for (V2Endpoint endpoint : v2.endpoints) {
endpoint.versionId = "2";
}
}
}
return v2Services;
}
private List<V2Endpoint> toV2Endpoints(ProjectData project, List<Endpoint> v3Endpoints) {
Map<String, V2Endpoint> v2Endpoints = Maps.newHashMap();
for (Endpoint v3 : v3Endpoints) {
String key = v3.region;
V2Endpoint v2 = v2Endpoints.get(key);
if (v2 == null) {
v2 = new V2Endpoint();
v2Endpoints.put(key, v2);
v2.tenantId = "" + project.getId();
v2.region = v3.region;
}
if (v3.interfaceName.equals("public")) {
v2.publicURL = v3.url;
}
if (v3.interfaceName.equals("admin")) {
v2.adminURL = v3.url;
}
if (v3.interfaceName.equals("internal")) {
v2.internalURL = v3.url;
}
}
return Lists.newArrayList(v2Endpoints.values());
}
private Role toModel(ProjectData project, RoleData role) {
Role model = new Role();
model.id = "" + role.getId();
model.name = role.getName();
if (project != null) {
model.tenantId = "" + project.getId();
}
return model;
}
}