package io.fathom.cloud.identity; import io.fathom.cloud.CloudException; import io.fathom.cloud.WellKnownRoles; import io.fathom.cloud.identity.model.AuthenticatedUser; import io.fathom.cloud.identity.secrets.Secrets; import io.fathom.cloud.identity.services.IdentityService; import io.fathom.cloud.identity.state.AuthRepository; import io.fathom.cloud.protobuf.CloudCommons.TokenInfo; import io.fathom.cloud.protobuf.CloudCommons.TokenScope; 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.server.auth.SharedSecretTokenService; import io.fathom.cloud.server.auth.TokenAuth; import io.fathom.cloud.server.model.Project; import io.fathom.cloud.services.AuthService; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import com.google.inject.persist.Transactional; import com.google.protobuf.ByteString; @Singleton public class AuthServiceImpl implements AuthService { private static final Logger log = LoggerFactory.getLogger(AuthServiceImpl.class); @Inject LoginService loginService; @Inject AuthRepository authRepository; @Inject SharedSecretTokenService tokenService; @Inject Secrets secretService; @Inject IdentityService identityService; @Override @Transactional public Auth authenticate(Long projectId, String username, String password) throws CloudException { AuthenticatedUser authentication = loginService.authenticate(projectId, username, password); if (authentication == null) { return null; } TokenInfo tokenInfo = loginService.buildTokenInfo(authentication); return new TokenAuth(tokenInfo); } @Override @Transactional public List<Long> resolveProjectName(Auth auth, String projectName) throws CloudException { UserData userData = authRepository.getUsers().find(auth.getUser().getId()); if (userData == null) { log.warn("Unable to find user: {}", auth.getUser()); return null; } List<Long> projectIds = Lists.newArrayList(); for (ProjectRoles pr : userData.getProjectRolesList()) { long projectId = pr.getProject(); ProjectData project = authRepository.getProjects().find(projectId); if (project == null) { log.warn("Unable to find project: {}", projectId); continue; } if (projectName.equals(project.getName())) { projectIds.add(projectId); } } return projectIds; } @Override @Transactional public String createServiceToken(Auth auth, long instanceId) throws CloudException { long projectId = auth.getProject().getId(); if (projectId == 0) { throw new IllegalStateException(); } ProjectData project = authRepository.getProjects().find(projectId); if (project == null) { log.warn("Unable to find project: {}", auth.getProject()); return null; } TokenInfo.Builder b = TokenInfo.newBuilder(); b.setTokenScope(TokenScope.Project); b.setDomainId(project.getDomainId()); b.setProjectId(projectId); // TODO: Same roles as auth?? b.addRoles(WellKnownRoles.ROLE_ID_MEMBER); { AuthenticatedUser authenticatedUser = toAuthenticatedUser(auth); ByteString tokenSecret = secretService.buildTokenSecret(authenticatedUser); b.setTokenSecret(tokenSecret); // For now, we can't get the secret without going through a user // For now, we use the user's id. It provides some degree of // auditing. log.warn("Creating service token using user's credentials"); b.setUserId(auth.getUser().getId()); } b.setServiceToken(true); b.setInstanceId(instanceId); String tokenId = tokenService.encodeToken(b.build()); return tokenId; } @Override public String getIdentityUri(String baseUrl) { return baseUrl + "/v2.0"; } @Override public Long createProject(Auth auth, String projectName) throws CloudException { Auth.Domain domain = auth.findDomainWithAdminRole(); if (domain == null) { throw new WebApplicationException(Status.FORBIDDEN); } ProjectData.Builder b = ProjectData.newBuilder(); // if (!Strings.isNullOrEmpty(req.description)) { // b.setDescription(req.description); // } b.setName(projectName); b.setDomainId(domain.getId()); b.setEnabled(true); AuthenticatedUser owner = toAuthenticatedUser(auth); ProjectData created = identityService.createProject(b, owner, WellKnownRoles.ROLE_ID_ADMIN); return created.getId(); } public AuthenticatedUser toAuthenticatedUser(Auth auth) throws CloudException { TokenAuth tokenAuth = (TokenAuth) auth; TokenInfo tokenInfo = tokenAuth.getTokenInfo(); AuthenticatedUser authenticatedUser = loginService.authenticate(tokenInfo); return authenticatedUser; } @Override public Project findSystemProject() throws CloudException { log.warn("findSystemProject is very inefficient"); for (ProjectData project : authRepository.getProjects().list()) { if (project.getName().equals(SYSTEM_PROJECT_NAME)) { return new Project(project.getId()); } } return null; } }