diff options
-rw-r--r-- | README.md | 80 | ||||
-rw-r--r-- | cynagoauth.service | 6 | ||||
-rw-r--r-- | src/cynagoauth-launch.c | 66 | ||||
-rw-r--r-- | src/cynagoauth-server.c | 105 |
4 files changed, 207 insertions, 50 deletions
@@ -8,9 +8,8 @@ It currently only implments the client credential flow, checking the client identity using the Smack label. A tiny launcher, cynagoauth-launch, is provided to negociate the token and run the final client, setting CYNAGOAUTH_TOKEN environment -variable and substi - - +variable and substitute the patterns for the token of the +arguments of the launched program. LICENSE ------- @@ -24,18 +23,18 @@ DEPENDENCIES It depends of: - - json-c - - libmicrohttpd - - openssl - - libcurl - +- json-c +- libmicrohttpd +- openssl +- libcurl +- cynagora COMPILING --------- To compile and install it: -``` +```sh mkdir build cd build cmake .. @@ -45,8 +44,65 @@ make RFCs ---- -OAuth 2.0 Authorization Server Metadata: https://tools.ietf.org/html/rfc8414 +OAuth 2.0 Authorization Framework: <https://tools.ietf.org/html/rfc6749> + +OAuth 2.0 Authorization Server Metadata: <https://tools.ietf.org/html/rfc8414> + +OAuth 2.0 Dynamic Client Registration Protocol: <https://tools.ietf.org/html/rfc7591> + +OpenID Connect Discovery 1.0: <https://openid.net/specs/openid-connect-discovery-1_0.html> + +cynagoauth-server +----------------- + +```text +> cynagoauth-server -h + +usage: cynagoauth-server [options...] [interfaces...] + +Run a basic OAuth server, currently only implementing client credential +flow based on Smack labels and Cynagora backend. + +The interfaces specify ip adresses and port to listen. It must be of +the form [HOST][:SERVICE]. Default host: *, default port: 7777. +Examples: -OAuth 2.0 Dynamic Client Registration Protocol: https://tools.ietf.org/html/rfc7591 + localhost:5555 listen on loopback on port 5555 + *:1234 listen any interface on port 1234 + localhost listen on default port of localhost -OpenID Connect Discovery 1.0: https://openid.net/specs/openid-connect-discovery-1_0.html +Default interface if none is given: *:7777 + +Options: + + -h, --help this help + -s, --secure serves https + -u, --unsecure serves http +``` + +cynagoauth-launcher +------------------- + +```text +usage: cynagoauth-launch [options...] program [args...] + +Ask an OAuth2 server for an access token and launches the given program +with this retrieved token. The URL of the token end point to be queried +can be set by option (see below) or environment variable CYNAGOAUTH_URL. +The default value is http://localhost:7777/tok + +When launched the program has the following environment variables defined: + + - the access token CYNAGOAUTH_TOKEN + +The arguments of the program to launch are scanned and patterns for the token +are substituted by the effective value of the token. The default pattern is @t + +Options: + + -h, --help this help + -n, --name NAME name of the environement variable to set + -r, --replace PATTERN redefine the pattern to be replaced + -t, --token TOKEN the token to use, token end point is not queried + -u, --url URL URL of the token end point +``` diff --git a/cynagoauth.service b/cynagoauth.service index cd84afb..9468a7a 100644 --- a/cynagoauth.service +++ b/cynagoauth.service @@ -3,9 +3,9 @@ Description=Authorization server OAuth2 BindsTo=cynagora.service [Service] -#User=daemon -#Group=nobody -#SupplementaryGroups=cynagora +User=daemon +Group=nobody +SupplementaryGroups=cynagora ExecStart=/usr/bin/cynagoauth-server Restart=on-failure RestartSec=5 diff --git a/src/cynagoauth-launch.c b/src/cynagoauth-launch.c index a762877..b2d6401 100644 --- a/src/cynagoauth-launch.c +++ b/src/cynagoauth-launch.c @@ -31,6 +31,12 @@ #if !defined(DEFAULTNAME) # define DEFAULTNAME "CYNAGOAUTH_TOKEN" #endif +#if !defined(DEFAULTNAMETYPE) +# define DEFAULTNAMETYPE DEFAULTNAME"_TYPE" +#endif +#if !defined(DEFAULTNAMEEXPIRE) +# define DEFAULTNAMEEXPIRE DEFAULTNAME"_EXPIRE" +#endif #if !defined(VARURL) # define VARURL "CYNAGOAUTH_URL" #endif @@ -38,9 +44,10 @@ # define DEFAULTURL "http://localhost:7777/tok" #endif -const char shortopts[] = "+n:r:t:u:"; +const char shortopts[] = "+hn:r:t:u:"; const struct option longopts[] = { + { "help", 0, 0, 'h' }, { "name", 1, 0, 'n' }, { "replace", 1, 0, 'r' }, { "token", 1, 0, 't' }, @@ -48,6 +55,39 @@ const struct option longopts[] = { { 0, 0, 0, 0 } }; +const char helpmsg[] = + "\n" + "usage: %s [options...] program [args...]\n" + "\n" + "Ask an OAuth2 server for an access token and launches the given program\n" + "with this retrieved token. The URL of the token end point to be queried\n" + "can be set by option (see below) or environment variable "VARURL".\n" + "The default value is "DEFAULTURL"\n" + "\n" + "When launched the program has the following environment variables defined:\n" + "\n" + " - the access token "DEFAULTNAME"\n" + "\n" + "The arguments of the program to launch are scanned and patterns for the token\n" + "are substituted by the effective value of the token. The default pattern is @t\n" + "\n" + "Options:\n" + "\n" + " -h, --help this help\n" + " -n, --name NAME name of the environement variable to set\n" + " -r, --replace PATTERN redefine the pattern to be replaced\n" + " -t, --token TOKEN the token to use, token end point is not queried\n" + " -u, --url URL URL of the token end point\n" + "\n" +; + +void printhelp(char *prog) +{ + prog = strchr(prog, '/') ? strrchr(prog, '/') + 1 : prog; + printf(helpmsg, prog); + exit(0); +} + char *optname = NULL; char *optreplace = NULL; char *opttoken = NULL; @@ -67,7 +107,8 @@ char *rewrite_search(char *string, const char *defs[], int *idxpat) for (iit = 0 ; (spat = defs[iit]) ; iit += 2) { if (*spat) { sit = strstr(string, spat); - if (sit && (sfound == NULL || sfound > sit)) { + if (sit && (sfound == NULL || sfound > sit || + (sfound == sit && strlen(spat) > strlen(defs[ifound])))) { ifound = iit; sfound = sit; } @@ -132,17 +173,9 @@ char *rewrite(char *arg, const char *token) { const char *defs[5]; - if (optreplace) { - defs[0] = optreplace; - defs[1] = token; - defs[4] = NULL; - } else { - defs[0] = "@t"; - defs[1] = token; - defs[2] = "@@"; - defs[3] = "@"; - defs[4] = NULL; - } + defs[0] = optreplace ?: "@t"; + defs[1] = token; + defs[2] = NULL; return rewrite_replace(arg, defs); } @@ -191,22 +224,21 @@ void process_arguments(int ac, char **av) return; } switch (optid) { + case 'h': + printhelp(av[0]); + break; case 'n': optname = optarg; break; - case 'r': optreplace = optarg; break; - case 't': opttoken = optarg; break; - case 'u': opturl = optarg; break; - default: fprintf(stderr, "Bad option detected"); exit(1); diff --git a/src/cynagoauth-server.c b/src/cynagoauth-server.c index f826c88..627e5d6 100644 --- a/src/cynagoauth-server.c +++ b/src/cynagoauth-server.c @@ -26,6 +26,7 @@ #include <poll.h> #include <netdb.h> #include <sys/socket.h> +#include <getopt.h> #include <microhttpd.h> #include <json-c/json.h> @@ -54,6 +55,47 @@ # define ENVHOSTS "CYNAGOAUTH_HOSTS_SPEC" #endif +static const char shortopts[] = "hs"; + +static const struct option longopts[] = { + { "help", 0, 0, 'h' }, + { "secure", 0, 0, 's' }, + { "unsecure", 0, 0, 'u' }, + { 0, 0, 0, 0 } +}; + +const char helpmsg[] = + "\n" + "usage: %s [options...] [interfaces...]\n" + "\n" + "Run a basic OAuth server, currently only implementing client credential\n" + "flow based on Smack labels and Cynagora backend.\n" + "\n" + "The interfaces specify ip adresses and port to listen. It must be of\n" + "the form [HOST][:SERVICE]. Default host: *, default port: "DEFAULTPORT".\n" + "Examples:\n" + "\n" + " localhost:5555 listen on loopback on port 5555\n" + " *:1234 listen any interface on port 1234\n" + " localhost listen on default port of localhost\n" + "\n" + "Default interface if none is given: "DEFAULTHOSTS"\n" + "\n" + "Options:\n" + "\n" + " -h, --help this help\n" + " -s, --secure serves https\n" + " -u, --unsecure serves http\n" + "\n" +; + +void printhelp(char *prog) +{ + prog = strchr(prog, '/') ? strrchr(prog, '/') + 1 : prog; + printf(helpmsg, prog); + exit(0); +} + static char cert[] = "-----BEGIN CERTIFICATE-----\n" "MIID5TCCAk2gAwIBAgIUBJtxecHlDMYCJfnDLqo8iWmNREkwDQYJKoZIhvcNAQEL\n" @@ -644,6 +686,10 @@ int access_handler( return MHD_YES; } +/****************************************************************************/ +/*** SETTING ***/ +/****************************************************************************/ + int openhost(const char *hostname) { int rc, fd; @@ -747,19 +793,46 @@ void main(int ac, char **av) struct MHD_Daemon *mhd; const union MHD_DaemonInfo *info; MHD_UNSIGNED_LONG_LONG to; - int i, r, n, s; - unsigned int flags = 0; + int i, r, n, s, o; + unsigned int flags; struct pollfd pfds[20]; credset_create(&creds); uidset_create(&uids, 50); - i = 1; - if (av[i] && !strcmp(av[i], "-s")) { - flags |= MHD_USE_TLS; - i++; + flags = 0; + while((o = getopt_long(ac, av, shortopts, longopts, NULL)) >= 0) { + switch (o) { + case 'h': + printhelp(av[0]); + break; + case 's': + flags |= MHD_USE_TLS; + break; + case 'u': + flags &= ~MHD_USE_TLS; + break; + default: + fprintf(stderr, "Bad option detected"); + exit(1); + break; + } } + /* open hosts */ + s = (int)(sizeof pfds / sizeof *pfds); + n = 1; + if (!av[optind]) + n += openhosts(getenv(ENVHOSTS)?:DEFAULTHOSTS, &pfds[n], s - n); + else + while (av[optind]) + n += openhosts(av[optind++], &pfds[n], s - n); + if (n == 0) { + fprintf(stderr, "not listening"); + exit(1); + } + + /* instanciate LMHD */ mhd = MHD_start_daemon( MHD_USE_EPOLL | MHD_USE_DEBUG @@ -772,43 +845,38 @@ void main(int ac, char **av) flags ? MHD_OPTION_HTTPS_MEM_KEY : MHD_OPTION_END, key, MHD_OPTION_HTTPS_MEM_CERT, cert, MHD_OPTION_END); - if (NULL == mhd) { - fprintf(stderr, "cant't start http server\n"); + fprintf(stderr, "cant't create http server\n"); exit(1); } + /* add LMHD to polls */ info = MHD_get_daemon_info(mhd, MHD_DAEMON_INFO_EPOLL_FD); if (info == NULL) { fprintf(stderr, "cant't get http server\n"); MHD_stop_daemon(mhd); exit(2); } - - s = (int)(sizeof pfds / sizeof *pfds); pfds[0].fd = info->epoll_fd; pfds[0].events = POLLIN; - n = 1; - - /* open hosts */ - if (!av[i]) - n += openhosts(getenv(ENVHOSTS)?:DEFAULTHOSTS, &pfds[n], s - n); - else - while (av[i]) - n += openhosts(av[i++], &pfds[n], s - n); /* main loop */ for(;;) { + /* get timeout */ if (MHD_get_timeout(mhd, &to) == MHD_NO) i = -1; else i = (int)to; + + /* wait */ r = poll(pfds, n, i); if (r < 0) { fprintf(stderr, "poll error\n"); MHD_stop_daemon (mhd); exit(3); } + + /* dispatch LMHD */ if (r == 0 || (pfds[0].revents & POLLIN)) MHD_run(mhd); if (pfds[0].revents & POLLHUP) { @@ -817,6 +885,7 @@ void main(int ac, char **av) exit(4); } + /* dispatch connections listeners */ for (i = 1 ; i < n ; i++) { if (pfds[i].revents & POLLIN) makeconnection(mhd, pfds[i].fd); |