kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

auth.c (4011B)



      1 /*
      2  * Copyright (c) 2014 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/param.h>
     18 #include <sys/types.h>
     19 
     20 #include <ctype.h>
     21 
     22 #include "kore.h"
     23 #include "http.h"
     24 
     25 TAILQ_HEAD(, kore_auth)		auth_list;
     26 
     27 void
     28 kore_auth_init(void)
     29 {
     30 	TAILQ_INIT(&auth_list);
     31 }
     32 
     33 int
     34 kore_auth_new(const char *name)
     35 {
     36 	struct kore_auth	*auth;
     37 
     38 	if (kore_auth_lookup(name) != NULL)
     39 		return (KORE_RESULT_ERROR);
     40 
     41 	auth = kore_malloc(sizeof(*auth));
     42 	auth->type = 0;
     43 	auth->value = NULL;
     44 	auth->redirect = NULL;
     45 	auth->validator = NULL;
     46 	auth->name = kore_strdup(name);
     47 
     48 	TAILQ_INSERT_TAIL(&auth_list, auth, list);
     49 
     50 	return (KORE_RESULT_OK);
     51 }
     52 
     53 int
     54 kore_auth_run(struct http_request *req, struct kore_auth *auth)
     55 {
     56 	int		r;
     57 
     58 	kore_debug("kore_auth(%p, %p)", req, auth);
     59 
     60 	switch (auth->type) {
     61 	case KORE_AUTH_TYPE_COOKIE:
     62 		r = kore_auth_cookie(req, auth);
     63 		break;
     64 	case KORE_AUTH_TYPE_HEADER:
     65 		r = kore_auth_header(req, auth);
     66 		break;
     67 	case KORE_AUTH_TYPE_REQUEST:
     68 		r = kore_auth_request(req, auth);
     69 		break;
     70 	default:
     71 		kore_log(LOG_NOTICE, "unknown auth type %d", auth->type);
     72 		return (KORE_RESULT_ERROR);
     73 	}
     74 
     75 	switch (r) {
     76 	case KORE_RESULT_OK:
     77 		req->flags |= HTTP_REQUEST_AUTHED;
     78 		kore_debug("kore_auth_run() for %s successful", req->path);
     79 		/* FALLTHROUGH */
     80 	case KORE_RESULT_RETRY:
     81 		return (r);
     82 	default:
     83 		break;
     84 	}
     85 
     86 	/* Authentication types of "request" send their own HTTP responses. */
     87 	if (auth->type == KORE_AUTH_TYPE_REQUEST)
     88 		return (r);
     89 
     90 	kore_debug("kore_auth_run() for %s failed", req->path);
     91 
     92 	if (auth->redirect == NULL) {
     93 		http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0);
     94 		return (KORE_RESULT_ERROR);
     95 	}
     96 
     97 	http_response_header(req, "location", auth->redirect);
     98 	http_response(req, HTTP_STATUS_FOUND, NULL, 0);
     99 
    100 	return (KORE_RESULT_ERROR);
    101 }
    102 
    103 int
    104 kore_auth_cookie(struct http_request *req, struct kore_auth *auth)
    105 {
    106 	const char	*hdr;
    107 	int		i, v;
    108 	size_t		len, slen;
    109 	char		*value, *c, *cookie, *cookies[HTTP_MAX_COOKIES];
    110 
    111 	if (!http_request_header(req, "cookie", &hdr))
    112 		return (KORE_RESULT_ERROR);
    113 
    114 	cookie = kore_strdup(hdr);
    115 
    116 	slen = strlen(auth->value);
    117 	v = kore_split_string(cookie, ";", cookies, HTTP_MAX_COOKIES);
    118 	for (i = 0; i < v; i++) {
    119 		for (c = cookies[i]; isspace(*(unsigned char *)c); c++)
    120 			;
    121 
    122 		len = MIN(slen, strlen(cookies[i]));
    123 		if (!strncmp(c, auth->value, len))
    124 			break;
    125 	}
    126 
    127 	if (i == v) {
    128 		kore_free(cookie);
    129 		return (KORE_RESULT_ERROR);
    130 	}
    131 
    132 	c = cookies[i];
    133 	if ((value = strchr(c, '=')) == NULL) {
    134 		kore_free(cookie);
    135 		return (KORE_RESULT_ERROR);
    136 	}
    137 
    138 	i = kore_validator_check(req, auth->validator, ++value);
    139 	kore_free(cookie);
    140 
    141 	return (i);
    142 }
    143 
    144 int
    145 kore_auth_header(struct http_request *req, struct kore_auth *auth)
    146 {
    147 	const char	*header;
    148 
    149 	if (!http_request_header(req, auth->value, &header))
    150 		return (KORE_RESULT_ERROR);
    151 
    152 	return (kore_validator_check(req, auth->validator, header));
    153 }
    154 
    155 int
    156 kore_auth_request(struct http_request *req, struct kore_auth *auth)
    157 {
    158 	int		ret;
    159 
    160 	req->flags |= HTTP_VALIDATOR_IS_REQUEST;
    161 	ret = kore_validator_check(req, auth->validator, req);
    162 	req->flags &= ~HTTP_VALIDATOR_IS_REQUEST;
    163 
    164 	return (ret);
    165 }
    166 
    167 struct kore_auth *
    168 kore_auth_lookup(const char *name)
    169 {
    170 	struct kore_auth	*auth;
    171 
    172 	TAILQ_FOREACH(auth, &auth_list, list) {
    173 		if (!strcmp(auth->name, name))
    174 			return (auth);
    175 	}
    176 
    177 	return (NULL);
    178 }