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 (3845B)



      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 	switch (auth->type) {
     59 	case KORE_AUTH_TYPE_COOKIE:
     60 		r = kore_auth_cookie(req, auth);
     61 		break;
     62 	case KORE_AUTH_TYPE_HEADER:
     63 		r = kore_auth_header(req, auth);
     64 		break;
     65 	case KORE_AUTH_TYPE_REQUEST:
     66 		r = kore_auth_request(req, auth);
     67 		break;
     68 	default:
     69 		kore_log(LOG_NOTICE, "unknown auth type %d", auth->type);
     70 		return (KORE_RESULT_ERROR);
     71 	}
     72 
     73 	switch (r) {
     74 	case KORE_RESULT_OK:
     75 		req->flags |= HTTP_REQUEST_AUTHED;
     76 		/* FALLTHROUGH */
     77 	case KORE_RESULT_RETRY:
     78 		return (r);
     79 	default:
     80 		break;
     81 	}
     82 
     83 	/* Authentication types of "request" send their own HTTP responses. */
     84 	if (auth->type == KORE_AUTH_TYPE_REQUEST)
     85 		return (r);
     86 
     87 	if (auth->redirect == NULL) {
     88 		http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0);
     89 		return (KORE_RESULT_ERROR);
     90 	}
     91 
     92 	http_response_header(req, "location", auth->redirect);
     93 	http_response(req, HTTP_STATUS_FOUND, NULL, 0);
     94 
     95 	return (KORE_RESULT_ERROR);
     96 }
     97 
     98 int
     99 kore_auth_cookie(struct http_request *req, struct kore_auth *auth)
    100 {
    101 	const char	*hdr;
    102 	int		i, v;
    103 	size_t		len, slen;
    104 	char		*value, *c, *cookie, *cookies[HTTP_MAX_COOKIES];
    105 
    106 	if (!http_request_header(req, "cookie", &hdr))
    107 		return (KORE_RESULT_ERROR);
    108 
    109 	cookie = kore_strdup(hdr);
    110 
    111 	slen = strlen(auth->value);
    112 	v = kore_split_string(cookie, ";", cookies, HTTP_MAX_COOKIES);
    113 	for (i = 0; i < v; i++) {
    114 		for (c = cookies[i]; isspace(*(unsigned char *)c); c++)
    115 			;
    116 
    117 		len = MIN(slen, strlen(cookies[i]));
    118 		if (!strncmp(c, auth->value, len))
    119 			break;
    120 	}
    121 
    122 	if (i == v) {
    123 		kore_free(cookie);
    124 		return (KORE_RESULT_ERROR);
    125 	}
    126 
    127 	c = cookies[i];
    128 	if ((value = strchr(c, '=')) == NULL) {
    129 		kore_free(cookie);
    130 		return (KORE_RESULT_ERROR);
    131 	}
    132 
    133 	i = kore_validator_check(req, auth->validator, ++value);
    134 	kore_free(cookie);
    135 
    136 	return (i);
    137 }
    138 
    139 int
    140 kore_auth_header(struct http_request *req, struct kore_auth *auth)
    141 {
    142 	const char	*header;
    143 
    144 	if (!http_request_header(req, auth->value, &header))
    145 		return (KORE_RESULT_ERROR);
    146 
    147 	return (kore_validator_check(req, auth->validator, header));
    148 }
    149 
    150 int
    151 kore_auth_request(struct http_request *req, struct kore_auth *auth)
    152 {
    153 	int		ret;
    154 
    155 	req->flags |= HTTP_VALIDATOR_IS_REQUEST;
    156 	ret = kore_validator_check(req, auth->validator, req);
    157 	req->flags &= ~HTTP_VALIDATOR_IS_REQUEST;
    158 
    159 	return (ret);
    160 }
    161 
    162 struct kore_auth *
    163 kore_auth_lookup(const char *name)
    164 {
    165 	struct kore_auth	*auth;
    166 
    167 	TAILQ_FOREACH(auth, &auth_list, list) {
    168 		if (!strcmp(auth->name, name))
    169 			return (auth);
    170 	}
    171 
    172 	return (NULL);
    173 }