Skip to content
This repository has been archived by the owner on Nov 11, 2024. It is now read-only.

Added user service methods and tests #661

Merged
merged 3 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
implementation project(':dev.galasa.framework')
implementation project(':dev.galasa.framework.api.beans')
implementation project(':dev.galasa.framework.api.common')
implementation project(':dev.galasa.framework.api.users')

implementation 'org.apache.commons:commons-lang3:3.14.0'
implementation 'dev.galasa:com.auth0.jwt:4.4.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import dev.galasa.framework.spi.auth.IAuthStoreService;
import dev.galasa.framework.spi.auth.IInternalAuthToken;
import dev.galasa.framework.spi.auth.IInternalUser;
import dev.galasa.framework.spi.auth.UserDoc;
import dev.galasa.framework.spi.auth.AuthStoreException;

public class AuthTokensRoute extends BaseRoute {
Expand Down Expand Up @@ -102,7 +103,7 @@ public HttpServletResponse handleGetRequest(String pathInfo, QueryParameters que

// Convert the token received from the auth store into the token bean that will
// be returned as JSON
List<AuthToken>tokensToReturn = convertAuthStoreTokenIntoTokenBeans(authTokensFromAuthStore);
List<AuthToken> tokensToReturn = convertAuthStoreTokenIntoTokenBeans(authTokensFromAuthStore);

return getResponseBuilder().buildResponse(request, response, "application/json",
getTokensAsJsonString(tokensToReturn), HttpServletResponse.SC_OK);
Expand Down Expand Up @@ -182,6 +183,8 @@ public HttpServletResponse handlePostRequest(String pathInfo, QueryParameters qu
addTokenToAuthStore(requestPayload.getClientId(), jwt, tokenDescription);
}

recordUserJustLoggedIn(isLoggingIntoWebUI(requestPayload.getRefreshToken(), tokenDescription), jwt);

} else {
logger.info("Unable to get new bearer and refresh tokens from issuer.");

Expand Down Expand Up @@ -295,6 +298,29 @@ private List<AuthToken> convertAuthStoreTokenIntoTokenBeans(List<IInternalAuthTo

}

private void recordUserJustLoggedIn(boolean isWebUI, String jwt)
throws InternalServletException, AuthStoreException {

JwtWrapper jwtWrapper = new JwtWrapper(jwt, env);
String loginId = jwtWrapper.getUsername();
String clientName = "rest-api";
aashir21 marked this conversation as resolved.
Show resolved Hide resolved

UserDoc userDoc = new UserDoc(loginId);

if (isWebUI) {
clientName = "web-ui";
}

userDoc = authStoreService.getUserByLoginId(loginId);

if (userDoc == null) {
authStoreService.createUser(loginId, clientName);
} else {
authStoreService.updateUserClientActivity(loginId, clientName);
}

}

private void validateLoginId(String loginId, String servletPath) throws InternalServletException {

if (loginId == null || loginId.trim().length() == 0) {
Expand All @@ -303,4 +329,11 @@ private void validateLoginId(String loginId, String servletPath) throws Internal
}

}

private boolean isLoggingIntoWebUI(String refreshToken, String tokenDescription) {

return (refreshToken == null && tokenDescription == null);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ public void testAuthPostRequestWithInvalidRequestPayloadReturnsBadRequestError()
@Test
public void testAuthPostRequestWithValidRefreshTokenRequestPayloadReturnsJWT() throws Exception {
// Given...
String dummyJwt = "this-is-a-jwt";
String dummyJwt = DUMMY_JWT;
String dummyRefreshToken = "this-is-a-refresh-token";
String mockResponseJson = buildTokenResponse(dummyJwt, dummyRefreshToken);

Expand Down Expand Up @@ -723,7 +723,7 @@ public void testAuthPostRequestWithDescriptionInRequestReturnsJWTAndStoresTokenI
@Test
public void testAuthPostRequestWithValidAuthCodeRequestPayloadReturnsJWT() throws Exception {
// Given...
String dummyJwt = "this-is-a-jwt";
String dummyJwt = DUMMY_JWT;
String dummyRefreshToken = "this-is-a-refresh-token";
String mockResponseJson = buildTokenResponse(dummyJwt, dummyRefreshToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import dev.galasa.framework.spi.auth.IAuthStoreService;
import dev.galasa.framework.spi.auth.IInternalAuthToken;
import dev.galasa.framework.spi.auth.IInternalUser;
import dev.galasa.framework.spi.auth.UserDoc;
import dev.galasa.framework.spi.utils.ITimeService;
import dev.galasa.framework.spi.auth.AuthStoreException;
import dev.galasa.framework.spi.auth.FrontendClient;

public class MockAuthStoreService implements IAuthStoreService {

Expand Down Expand Up @@ -100,4 +102,48 @@ public List<IInternalAuthToken> getTokensByLoginId(String loginId) throws AuthSt
}
return tokensToReturn;
}

@Override
public List<UserDoc> getAllUsers() throws AuthStoreException {

List<UserDoc> users = new ArrayList<>();

UserDoc user1 = new UserDoc("user-1");
UserDoc user2 = new UserDoc("user-2");

user1.setUserNumber("docid");
user1.setVersion("revVersion");
user1.setClients(List.of(new FrontendClient("web-ui", Instant.parse("2024-10-18T14:49:50.096329Z"))));

user2.setUserNumber("docid-2");
user2.setVersion("revVersion2");
user2.setClients(List.of(new FrontendClient("rest-api", Instant.parse("2024-10-18T14:49:50.096329Z"))));

users.add(user1);
users.add(user2);

return users;
}

@Override
public void createUser(String loginId, String clientName) throws AuthStoreException {
// Do nothing
}

@Override
public UserDoc getUserByLoginId(String loginId) throws AuthStoreException {

UserDoc user = new UserDoc(loginId);

user.setUserNumber("docid");
user.setVersion("revVersion");
user.setClients(List.of(new FrontendClient("web-ui", Instant.parse("2024-10-18T14:49:50.096329Z"))));

return user;
}

@Override
public void updateUserClientActivity(String loginId, String clientName) throws AuthStoreException {
// Do nothing
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ paths:
- name: loginId
in: query
description: The loginId of the user whose details will be returned. #If the keyword of 'me' is used, the details of the requesting user will be returned.
required: true
required: false
schema:
type: string
responses:
Expand Down Expand Up @@ -1996,9 +1996,30 @@ components:
UserData:
type: object
properties:
login_id:
id:
type: string
description: The ID representing the user record in CouchDB.
aashir21 marked this conversation as resolved.
Show resolved Hide resolved
login-id:
type: string
description: The ID representing the user's username. Returned from queries about users.
clients:
type: array
description: The list of client activities, containing client names and last login times.
items:
$ref: '#/components/schemas/FrontendClient'
url:
type: string
description: The API URL for accessing the user data.
FrontendClient:
type: object
properties:
client-name:
type: string
description: The name of the client (e.g., "web-ui" or "rest-api").
last-login:
type: string
format: date-time
description: The timestamp of the user's last login on the respective client.
Requestors:
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
import dev.galasa.framework.api.common.Environment;
import dev.galasa.framework.api.common.SystemEnvironment;
import dev.galasa.framework.spi.IFramework;
import dev.galasa.framework.spi.auth.IAuthStoreService;

@Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE, property = {
"osgi.http.whiteboard.servlet.pattern=/users/*" }, name = "Galasa Users microservice")
public class UsersServlet extends BaseServlet {

@Reference
private IFramework framework;
protected IFramework framework;

public static final String QUERY_PARAM_LOGIN_ID = "loginId";

Expand All @@ -49,7 +50,8 @@ public void init() throws ServletException {

super.init();

addRoute(new UsersRoute(getResponseBuilder(), framework, env));
IAuthStoreService authStoreService = framework.getAuthStoreService();
addRoute(new UsersRoute(getResponseBuilder(), framework, env,authStoreService));

logger.info("Galasa Users API initialised");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import dev.galasa.framework.api.beans.generated.FrontendClient;
import dev.galasa.framework.api.beans.generated.UserData;
import dev.galasa.framework.api.common.BaseRoute;
import dev.galasa.framework.api.common.InternalServletException;
import dev.galasa.framework.api.common.QueryParameters;
import dev.galasa.framework.api.common.ResponseBuilder;
import dev.galasa.framework.api.common.Environment;
import dev.galasa.framework.api.common.ServletError;
import dev.galasa.framework.api.users.UsersServlet;
import dev.galasa.framework.api.common.JwtWrapper;
import dev.galasa.framework.api.beans.generated.UserData;

import dev.galasa.framework.spi.FrameworkException;
import dev.galasa.framework.spi.IFramework;

import static dev.galasa.framework.api.common.ServletErrorMessage.*;
import dev.galasa.framework.spi.auth.AuthStoreException;
import dev.galasa.framework.spi.auth.IAuthStoreService;
import dev.galasa.framework.spi.auth.UserDoc;

public class UsersRoute extends BaseRoute {

Expand All @@ -38,11 +40,14 @@ public class UsersRoute extends BaseRoute {

private IFramework framework;
private Environment env;
private IAuthStoreService authStoreService;

public UsersRoute(ResponseBuilder responseBuilder, IFramework framework, Environment env) {
public UsersRoute(ResponseBuilder responseBuilder, IFramework framework, Environment env,
aashir21 marked this conversation as resolved.
Show resolved Hide resolved
IAuthStoreService authStoreService) {
super(responseBuilder, path);
this.framework = framework;
this.env = env;
this.authStoreService = authStoreService;
}

@Override
Expand All @@ -52,44 +57,97 @@ public HttpServletResponse handleGetRequest(String pathInfo, QueryParameters que

logger.info("UserRoute: handleGetRequest() entered.");

validateQueryParam(queryParams, request.getServletPath());
List<UserData> usersList = new ArrayList<>();
String payloadContent = "{}";
aashir21 marked this conversation as resolved.
Show resolved Hide resolved

List<UserData> usersList = getUsersList(request);
String loginId = queryParams.getSingleString(UsersServlet.QUERY_PARAM_LOGIN_ID, null);

if (loginId != null) {
usersList = getUserByLoginIdList(request, loginId);
}
else{
List<UserDoc> users = authStoreService.getAllUsers();
usersList = convertAllUsersToUserBean(users);
}

String payloadContent = gson.toJson(usersList);
if (!usersList.isEmpty()) {
payloadContent = gson.toJson(usersList);
}

return getResponseBuilder().buildResponse(
request, response, "application/json", payloadContent, HttpServletResponse.SC_OK);
}

private void validateQueryParam(QueryParameters queryParams, String servletPath) throws InternalServletException {
private List<UserData> getUserByLoginIdList(HttpServletRequest request, String loginId)
throws InternalServletException, AuthStoreException {

String loginId = queryParams.getSingleString(UsersServlet.QUERY_PARAM_LOGIN_ID, null);
List<UserData> usersList = new ArrayList<>();
JwtWrapper jwtWrapper = new JwtWrapper(request, env);
UserData userData = null;

if(loginId == null){
ServletError error = new ServletError(GAL5082_NO_LOGINID_PARAM_PROVIDED, servletPath);
throw new InternalServletException(error, HttpServletResponse.SC_BAD_REQUEST);
if (loginId.equals("me")) {
loginId = jwtWrapper.getUsername();
}

if (!loginId.trim().equalsIgnoreCase(QUERY_PARAMETER_LOGIN_ID_VALUE_MYSELF)) {
ServletError error = new ServletError(GAL5081_INVALID_QUERY_PARAM_VALUE, servletPath);
throw new InternalServletException(error, HttpServletResponse.SC_BAD_REQUEST);

UserDoc currentUser = authStoreService.getUserByLoginId(loginId);

if (currentUser != null) {
userData = convertUserDocToUserBean(currentUser);
usersList.add(userData);
}

return usersList;
}

private List<UserData> getUsersList(HttpServletRequest request) throws InternalServletException {
private UserData convertUserDocToUserBean(UserDoc user) {

UserData userData = new UserData();
JwtWrapper jwtWrapper = new JwtWrapper(request, env);

String extractedUsernameFromToken = jwtWrapper.getUsername();
// Map each client in user.getClients() to a new FrontendClient instance
List<FrontendClient> clients = user.getClients().stream()
.map(client -> {
FrontendClient newClient = new FrontendClient();
newClient.setClientName(client.getClientName());
newClient.setLastLogin(client.getLastLoggedIn().toString());
return newClient;
})
.collect(Collectors.toList());

userData.setLoginId(extractedUsernameFromToken);
userData.setLoginId(user.getLoginId());
userData.setid(user.getUserNumber());
userData.setclients(clients.toArray(new FrontendClient[0])); // Convert the list to an array

List<UserData> usersList = new ArrayList<>();
usersList.add(userData);
return userData;

return usersList;
}

private List<UserData> convertAllUsersToUserBean(List<UserDoc> users) {

List<UserData> convertedUserList = new ArrayList<>();

users.forEach(user -> {
aashir21 marked this conversation as resolved.
Show resolved Hide resolved

UserData userData = new UserData();

// Map each client in user.getClients() to a new FrontendClient instance
List<FrontendClient> clients = user.getClients().stream()
.map(client -> {
FrontendClient newClient = new FrontendClient();
newClient.setClientName(client.getClientName());
newClient.setLastLogin(client.getLastLoggedIn().toString());
return newClient;
})
.collect(Collectors.toList());

userData.setLoginId(user.getLoginId());
userData.setid(user.getUserNumber());
userData.setclients(clients.toArray(new FrontendClient[0]));
aashir21 marked this conversation as resolved.
Show resolved Hide resolved

convertedUserList.add(userData);

});

return convertedUserList;
}

}
Loading