added JWT demo programs
This commit is contained in:
parent
4d589ee8bf
commit
162bb122fc
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.o
|
||||
deps
|
||||
jansson
|
||||
libjwt
|
||||
src/server
|
||||
src/jwt_demo_hs256
|
||||
src/jwt_demo_rs256
|
||||
.gitignore
|
@ -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)
|
||||
|
38
src/http.c
38
src/http.c
@ -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
56
src/jwt_demo_hs256.c
Normal 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
74
src/jwt_demo_rs256.c
Normal 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
41
src/login.html
Normal 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>
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user