added JWT demo programs

This commit is contained in:
Godmar Back 2018-04-13 10:40:26 -04:00
parent 4d589ee8bf
commit 162bb122fc
7 changed files with 203 additions and 22 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
*.o
deps
jansson
libjwt
src/server
src/jwt_demo_hs256
src/jwt_demo_rs256
.gitignore

View File

@ -11,7 +11,10 @@ LDLIBS=-L$(DEP_LIB_DIR) -ljwt -ljansson -lcrypto -ldl
HEADERS=socket.h http.h hexdump.h buffer.h bufio.h
OBJ=main.o socket.o hexdump.o http.o bufio.o
all: server
OTHERS=jwt_demo_rs256 jwt_demo_hs256
all: server $(OTHERS)
$(OBJ) : $(HEADERS)
@ -19,4 +22,4 @@ server: $(OBJ)
$(CC) $(LDFLAGS) -o $@ $(OBJ) $(LDLIBS)
clean:
/bin/rm $(OBJ)
/bin/rm $(OBJ) $(OTHERS)

View File

@ -34,19 +34,19 @@ char * server_root; // root from which static files are served
/* Parse HTTP request line, setting req_method, req_path, and req_version. */
static int
static bool
http_parse_request(struct http_transaction *ta)
{
size_t req_offset;
ssize_t len = bufio_readline(ta->client->bufio, &req_offset);
if (len <= 0)
return len;
return false;
char *request = bufio_offset2ptr(ta->client->bufio, req_offset);
char *endptr;
char *method = strtok_r(request, " ", &endptr);
if (method == NULL)
return -1;
return false;
if (!strcmp(method, "GET"))
ta->req_method = HTTP_GET;
@ -57,37 +57,37 @@ http_parse_request(struct http_transaction *ta)
char *req_path = strtok_r(NULL, " ", &endptr);
if (req_path == NULL)
return -1;
return false;
ta->req_path = bufio_ptr2offset(ta->client->bufio, req_path);
char *http_version = strtok_r(NULL, CRLF, &endptr);
if (http_version == NULL) // would be HTTP 0.9
return -1;
return false;
if (!strcmp(http_version, "HTTP/1.1"))
ta->req_version = HTTP_1_1;
else if (!strcmp(http_version, "HTTP/1.0"))
ta->req_version = HTTP_1_0;
else
return -1;
return false;
return 0;
}
return true;
}
/* Process HTTP headers. */
static int
static bool
http_process_headers(struct http_transaction *ta)
{
for (;;) {
size_t header_offset;
ssize_t len = bufio_readline(ta->client->bufio, &header_offset);
char *header = bufio_offset2ptr(ta->client->bufio, header_offset);
if (len <= 0)
return len;
return false;
char *header = bufio_offset2ptr(ta->client->bufio, header_offset);
if (len == 2 && STARTS_WITH(header, CRLF)) // empty CRLF
return 0;
return true;
header[len-2] = '\0';
/* Each header field consists of a name followed by a
@ -100,7 +100,7 @@ http_process_headers(struct http_transaction *ta)
char *field_value = strtok_r(NULL, " \t", &endptr); // skip leading & trailing OWS
if (field_name == NULL)
return -1;
return false;
// printf("Header: %s: %s\n", field_name, field_value);
if (!strcasecmp(field_name, "Content-Length")) {
@ -109,8 +109,6 @@ http_process_headers(struct http_transaction *ta)
/* Handle other headers here. */
}
return 0;
}
const int MAX_HEADER_LEN = 2048;
@ -331,16 +329,16 @@ http_handle_transaction(struct http_client *self)
memset(&ta, 0, sizeof ta);
ta.client = self;
if (http_parse_request(&ta) == -1)
return -1;
if (!http_parse_request(&ta))
return false;
if (http_process_headers(&ta) == -1)
return -1;
if (!http_process_headers(&ta))
return false;
if (ta.req_content_len > 0) {
int rc = bufio_read(self->bufio, ta.req_content_len, &ta.req_body);
if (rc != ta.req_content_len)
return -1;
return false;
// To see the body, use this:
// char *body = bufio_offset2ptr(ta.client->bufio, ta.req_body);

56
src/jwt_demo_hs256.c Normal file
View File

@ -0,0 +1,56 @@
/*
* Quick demo of how to use libjwt using a HS256.
*
* @author gback, CS 3214, Spring 2018
*/
#include <jwt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
static const char * NEVER_EMBED_A_SECRET_IN_CODE = "supa secret";
int
main()
{
jwt_t *mytoken;
if (jwt_new(&mytoken))
perror("jwt_new"), exit(-1);
if (jwt_add_grant(mytoken, "sub", "user0"))
perror("jwt_add_grant sub"), exit(-1);
time_t now = time(NULL);
if (jwt_add_grant_int(mytoken, "iat", now))
perror("jwt_add_grant iat"), exit(-1);
if (jwt_add_grant_int(mytoken, "exp", now + 3600 * 24))
perror("jwt_add_grant exp"), exit(-1);
if (jwt_set_alg(mytoken, JWT_ALG_HS256,
(unsigned char *)NEVER_EMBED_A_SECRET_IN_CODE, strlen(NEVER_EMBED_A_SECRET_IN_CODE)))
perror("jwt_set_alg"), exit(-1);
printf("dump:\n");
if (jwt_dump_fp(mytoken, stdout, 1))
perror("jwt_dump_fp"), exit(-1);
char *encoded = jwt_encode_str(mytoken);
if (encoded == NULL)
perror("jwt_encode_str"), exit(-1);
printf("encoded as %s\nTry entering this at jwt.io\n", encoded);
jwt_t *ymtoken;
if (jwt_decode(&ymtoken, encoded,
(unsigned char *)NEVER_EMBED_A_SECRET_IN_CODE, strlen(NEVER_EMBED_A_SECRET_IN_CODE)))
perror("jwt_decode"), exit(-1);
char *grants = jwt_get_grants_json(ymtoken, NULL); // NULL means all
if (grants == NULL)
perror("jwt_get_grants_json"), exit(-1);
printf("redecoded: %s\n", grants);
}

74
src/jwt_demo_rs256.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Quick demo of how to use libjwt using a RS256.
* You must have created a private/public key pair like so:
*
* openssl genpkey -algorithm RSA -out myprivatekey.pem -pkeyopt rsa_keygen_bits:2048
* openssl rsa -in myprivatekey.pem -pubout > mykey.pub
*
* @author gback, CS 3214, Spring 2018
*/
#include <jwt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
unsigned char private_key[16384];
unsigned char public_key[16384];
static void
read_key(unsigned char *key, const char *name)
{
FILE *f = fopen(name, "r");
if (f == NULL)
perror("fopen"), exit(-1);
size_t len = fread(key, 1, 8192, f);
key[len] = '\0';
fclose(f);
}
int
main()
{
read_key(private_key, "myprivatekey.pem");
read_key(public_key, "mykey.pub");
jwt_t *mytoken;
if (jwt_new(&mytoken))
perror("jwt_new"), exit(-1);
if (jwt_add_grant(mytoken, "sub", "user0"))
perror("jwt_add_grant sub"), exit(-1);
time_t now = time(NULL);
if (jwt_add_grant_int(mytoken, "iat", now))
perror("jwt_add_grant iat"), exit(-1);
if (jwt_add_grant_int(mytoken, "exp", now + 3600 * 24))
perror("jwt_add_grant exp"), exit(-1);
if (jwt_set_alg(mytoken, JWT_ALG_RS256,
private_key, strlen((char *)private_key)))
perror("jwt_set_alg"), exit(-1);
printf("dump:\n");
if (jwt_dump_fp(mytoken, stdout, 1))
perror("jwt_dump_fp"), exit(-1);
char *encoded = jwt_encode_str(mytoken);
if (encoded == NULL)
perror("jwt_encode_str"), exit(-1);
printf("encoded as %s\nTry entering this at jwt.io\n", encoded);
jwt_t *ymtoken;
if (jwt_decode(&ymtoken, encoded, public_key, strlen((char *)public_key)))
perror("jwt_decode"), exit(-1);
char *grants = jwt_get_grants_json(ymtoken, NULL); // NULL means all
if (grants == NULL)
perror("jwt_get_grants_json"), exit(-1);
printf("redecoded: %s\n", grants);
}

41
src/login.html Normal file
View File

@ -0,0 +1,41 @@
<!doctype html>
<html>
<!-- minimal demo of expected login functionality -->
<body>
<form onsubmit="return login(this)">
Username: <input name="username" >
Password: <input name="password" >
<input type="submit"/>
</form>
<div id="result">The result of the request will appear here.</div>
<script>
const result = document.getElementById('result');
function login(form) {
fetch("/api/login",
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({
username: form.username.value,
password: form.password.value
})
}).then((res) => {
if (res.status == 200) {
res.json().then((data) => {
result.innerText = `Success: token ${JSON.stringify(data)}`;
});
} else {
result.innerText = `Received: ${res.status} ${res.statusText}`;
}
}).catch((error) => {
result.innerText = `Error: ${error.message}`;
});
return false; // prevent default action
}
</script>
</body>

View File

@ -23,6 +23,7 @@ server_loop(char *port_string)
{
int accepting_socket = socket_open_bind_listen(port_string, 1024);
for (;;) {
fprintf(stderr, "Waiting for client...\n");
int client_socket = socket_accept_client(accepting_socket);
if (client_socket == -1)
return;