Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce RBAC checking via custom authHandler function #218

Open
wants to merge 28 commits into
base: v1.x/staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
756b42c
Some prototype RBAC checking + unfinished comments
DivergentEuropeans May 24, 2021
37a9bd7
request->username works properly
DivergentEuropeans May 24, 2021
d11786a
Removed logging for TSO credentials
DivergentEuropeans May 25, 2021
552f551
Change up switch case logic to handle backwards compatibility
DivergentEuropeans May 31, 2021
56d3941
Moved core RBAC auth code from zowe-common-c into ZSS
DivergentEuropeans Jun 3, 2021
faa29df
Merge branch 'staging' of github.com:zowe/zowe-common-c into RBAC-sup…
DivergentEuropeans Jun 3, 2021
f6d670d
Made authHandlers into an array of structs
DivergentEuropeans Jun 7, 2021
f8e6a20
Clean-up + changed authType to string in httpServer.c
DivergentEuropeans Jun 7, 2021
1b55568
Missed a few things
DivergentEuropeans Jun 7, 2021
c5c9bac
Removed comment
DivergentEuropeans Jun 7, 2021
20ad412
Code review changes
DivergentEuropeans Jun 11, 2021
1673b5f
Removed unneeded comment
DivergentEuropeans Jun 11, 2021
632cb11
Some code cleanup
Jun 23, 2021
517679b
Revert back to integer authType
Jul 1, 2021
305ab94
Remove SERVICE_AUTH_NATIVE_WITH_SESSION_TOKEN_NO_RBAC
Jul 1, 2021
be35a36
Refactor authorization code
Jul 1, 2021
166c715
Provide ability to pass userData into AuthorizationCheck
Jul 2, 2021
be5f0e5
Minor refactoring
Jul 5, 2021
59fc275
Merge branch 'staging' of github.com:zowe/zowe-common-c into RBAC-sup…
DivergentEuropeans Aug 19, 2021
c5880dd
Merge branch 'rbac-code-cleanup' of https://github.com/lchudinov/zowe…
DivergentEuropeans Aug 19, 2021
16b4ef9
Merge branch 'rbac-refactoring' of https://github.com/lchudinov/zowe-…
DivergentEuropeans Aug 19, 2021
979e105
Merge branch 'staging' of github.com:zowe/zowe-common-c into RBAC-sup…
DivergentEuropeans Aug 29, 2021
9d7f631
Add return code for registerHttpAuthorizationHandler
Aug 31, 2021
2a1ab84
Merge pull request #233 from lchudinov/feature/add-return-code-for-re…
lchudinov Aug 31, 2021
e736e8d
Rename AuthorizationHandler to HttpAuthorize
Aug 31, 2021
2f45fb2
Merge pull request #234 from lchudinov/feature/rename-authorization-h…
ifakhrutdinov Aug 31, 2021
58bf017
Merge branch 'staging' of github.com:zowe/zowe-common-c into RBAC-sup…
DivergentEuropeans Sep 24, 2021
14a7225
Merge remote-tracking branch 'origin/staging' into RBAC-support
Nov 29, 2021
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
50 changes: 48 additions & 2 deletions c/httpserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -3349,6 +3349,27 @@ static int handleServiceFailed(HttpConversation *conversation,
return HTTP_SERVICE_FAILED;
}

static int checkAuthorization(HttpServer *server, HttpService *service, HttpRequest *request, HttpResponse *response) {
if (!request->authenticated) {
return FALSE;
}
if (service->authorizationType == SERVICE_AUTHORIZATION_TYPE_NONE) {
return TRUE;
}
int authorized = TRUE;
HttpAuthorizationHandler *handler = server->authorizationHandlerList;
while (handler) {
if (handler->authorizationType == service->authorizationType) {
authorized = handler->authorizeFunction(service, request, response, handler->userData);
if (!authorized) {
break;
}
}
handler = handler->next;
}
return authorized;
}

static int handleHttpService(HttpServer *server,
HttpService *service,
HttpRequest *request,
Expand Down Expand Up @@ -3435,8 +3456,9 @@ static int handleHttpService(HttpServer *server,
}
break;
}
int authorized = checkAuthorization(server, service, request, response);
#ifdef DEBUG
printf("service=%s authenticated=%d\n",service->name,request->authenticated);
printf("service=%s authenticated=%d authorized=%d\n",service->name,request->authenticated,authorized);
#endif
if (request->authenticated == FALSE){
if (service->authFlags & SERVICE_AUTH_FLAG_OPTIONAL) {
Expand All @@ -3445,6 +3467,8 @@ static int handleHttpService(HttpServer *server,
} else {
respondWithAuthError(response, &authResponse);
}
} else if (!authorized) {
respondWithError(response, HTTP_STATUS_FORBIDDEN, "Forbidden");
DivergentEuropeans marked this conversation as resolved.
Show resolved Hide resolved
// Response is finished on return
} else {

Expand Down Expand Up @@ -6001,7 +6025,29 @@ int mainHttpLoop(HttpServer *server){
return stcBaseMainLoop(base, MAIN_WAIT_MILLIS);
}


int registerHttpAuthorizationHandler(HttpServer *server, int authorizationType, HttpAuthorize *authorizeFunction, void *userData) {
if (authorizationType == SERVICE_AUTHORIZATION_TYPE_NONE) {
return 0;
}
HttpAuthorizationHandler *handler = (HttpAuthorizationHandler*) safeMalloc(sizeof(*handler), "HttpAuthorizationHandler");
if (handler) {
handler->authorizationType = authorizationType;
handler->authorizeFunction = authorizeFunction;
handler->userData = userData;
handler->next = NULL;
HttpAuthorizationHandler *head = server->authorizationHandlerList;
if (!head) {
server->authorizationHandlerList = handler;
} else {
while (head->next != NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit: you could've used first/last pointers to do O(1) insertion:

if (server->firstAuthHandler) {
  server->lastAuthHandler->next = handler;
} else {
  server->firstAuthHandler = handler;
}
server->lastAuthHandler = handler;

Or if you don't care about the current order:

handler->next = server->authorizationHandlerList;
server->authorizationHandlerList = handler;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation not so critical for now as we have only one authorization handler. It can be improved in the future when we for sure know what we want to optimize.

head = head->next;
}
head->next = handler;
}
return 0;
}
return -1;
}


/*
Expand Down
27 changes: 27 additions & 0 deletions h/httpserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ typedef int HttpServiceServe(struct HttpService_tag *service, HttpResponse *resp
typedef int AuthExtract(struct HttpService_tag *service, HttpRequest *request);
typedef int AuthValidate(struct HttpService_tag *service, HttpRequest *request);
typedef int HttpServiceInsertCustomHeaders(struct HttpService_tag *service, HttpResponse *response);
typedef int HttpAuthorize(struct HttpService_tag *service, HttpRequest *request, HttpResponse *response, void *userData);

/*
returns HTTP_SERVICE_SUCCESS or other fail codes in same group
Expand Down Expand Up @@ -205,8 +206,21 @@ typedef struct HttpService_tag{
AuthValidate *authValidateFunction;
#define SERVICE_AUTH_FLAG_OPTIONAL 1
int authFlags;
#define SERVICE_AUTHORIZATION_TYPE_DEFAULT 0
#define SERVICE_AUTHORIZATION_TYPE_NONE 1
// Range 2..99 is reserved for future use
#define SERVICE_AUTHORIZATION_TYPE_FIRST_CUSTOM 100
// SERVICE_AUTHORIZATION_TYPE_FIRST_CUSTOM and higher can be defined and used by an application.
int authorizationType;
} HttpService;

typedef struct HttpAuthorizationHandler_tag {
int authorizationType;
HttpAuthorize *authorizeFunction;
void *userData;
struct HttpAuthorizationHandler_tag *next;
} HttpAuthorizationHandler;

typedef struct HTTPServerConfig_tag {
int port;
HttpService *serviceList;
Expand All @@ -229,6 +243,7 @@ typedef struct HttpServer_tag{
uint64 serverInstanceUID; /* may be something smart at some point. Now just startup STCK */
void *sharedServiceMem; /* address shared by all HttpServices */
hashtable *loggingIdsByName; /* contains a map of pluginID -> loggingID */
HttpAuthorizationHandler *authorizationHandlerList;
} HttpServer;

typedef struct WSReadMachine_tag{
Expand Down Expand Up @@ -417,6 +432,18 @@ int httpServerSetSessionTokenKey(HttpServer *server, unsigned int size,

int registerHttpService(HttpServer *server, HttpService *service);


/*
* @brief Register an Authorization handler.
* @param server HTTP Server
* @param authorizationType
* @param authorizeFunction Function that performs authorization.
* The function has to return TRUE if the user successfully authorized, otherwise - FALSE.
* @param userData Additional data for authorizeFunction
* @return 0 on success, -1 on failure.
*/
int registerHttpAuthorizationHandler(HttpServer *server, int authorizationType, HttpAuthorize *authorizeFunction, void *userData);

HttpRequest *dequeueHttpRequest(HttpRequestParser *parser);
HttpRequestParser *makeHttpRequestParser(ShortLivedHeap *slh);
HttpResponse *makeHttpResponse(HttpRequest *request, ShortLivedHeap *slh, Socket *socket);
Expand Down