Commit 3fee8397 authored by Moritz Schlarb's avatar Moritz Schlarb

Update upstream source from tag 'upstream/2.3.10'

Update to upstream version '2.3.10'
with Debian dir f68103eb822d9d9ea4247e563342bc9d612e62e5
parents a17e39d1 c6886737
......@@ -48,3 +48,6 @@ reporting bugs, providing fixes, suggesting useful features or other:
Gergan Penkov <https://github.com/gergan>
Florian Weimer <https://github.com/fweimer>
Aaron Donovan <https://github.com/amdonov>
Hans Petter Bieker <https://github.com/hpbieker>
archzone <https://github.com/archzone>
Petteri Stenius <https://github.com/psteniusubi>
12/31/2018
- fix warning printout in oidc_delete_oldest_state_cookies
- release 2.3.10
12/16/2018
- fix encryption buffer tag length mismatch
12/06/2018
- retain the unparsed URL path in current/original URL determination, and thereby preserve
and support URL-encoded characters in paths when redirecting back to the original URL
- add state to code exchange token requests only in multi-provider setups; see #402
- optionally delete the oldest state cookie(s); see #399
- bump to 2.3.10rc3
11/29/2018
- add support for refreshing an access token associated with an OIDC session using OIDCRefreshAccessTokenBeforeExpiry
- bump to 2.3.10rc0
11/15/2018
- release 2.3.9
11/13/2018
- fix parsing of cookie name in OIDCOAuthAcceptTokenAs when the cookie option is not listed last
- bump to 2.3.9rc7
11/12/2018
- fix OAuth 2.0 RS config check when OIDCOAuthServerMetadataURL is set; thanks @psteniusubi
- bump to 2.3.9rc6
10/24/2018
- add support for draft https://www.ietf.org/id/draft-ietf-oauth-mtls-12.txt:
OAuth 2.0 Mutual TLS Client Certificate Bound Access Tokens
when running as an OAuth 2.0 RS, validating cnf["x5t#S256"] claims.
- bump to 2.3.9rc5
10/17/2018
- ignore/trim spaces in X-Forwarded-* headers
- deal with forwarding proxy setups; see #395 ; thanks @archzone
- bump to 2.3.9rc4
10/02/2018
- improve OIDC backchannel logout based on config/Discover
- add OIDCProviderBackChannelLogoutSupported config primitive
- parse/interpret `backchannel_logout_supported` in Discovery document
- add `id_token_token_binding_cnf`: `tbh` to dynamic client registration metadata
- bump to 2.3.9rc3
10/01/2018
- support backchannel logout according to: https://openid.net/specs/openid-connect-backchannel-1_0.html
- bump to 2.3.9rc2
10/01/2018
- add test-cmd command to generate hashes base64urlencoded inputs (cnf/tbh claims)
09/30/2018
- support Token Binding for Access Tokens according to: https://tools.ietf.org/html/draft-ietf-oauth-token-binding
- bump to 2.3.9rc1
09/16/2018
- support nested arrays in Require claim authorization evaluation; see #392; thanks @hpbieker
- bump to 2.3.9rc0
09/12/2018
- fix return result FALSE when JWT payload parsing fails; see #389; thanks @amdonov
- release 2.3.8
......
......@@ -41,8 +41,10 @@ of claims provided in the `id_token`/ `userinfo` claims.
- [RFC7 7636 - Proof Key for Code Exchange by OAuth Public Clients](https://tools.ietf.org/html/rfc7636)
- [OpenID Connect Session Management 1.0](http://openid.net/specs/openid-connect-session-1_0.html) *(implementers draft; see the [Wiki](https://github.com/zmartzone/mod_auth_openidc/wiki/Session-Management) for information on how to configure it)*
- [OpenID Connect Front-Channel Logout 1.0](http://openid.net/specs/openid-connect-frontchannel-1_0.html) *(implementers draft)*
- [OpenID Connect Back-Channel Logout 1.0](https://openid.net/specs/openid-connect-backchannel-1_0.html) *(implementers draft)*
- [Encoding claims in the OAuth 2 state parameter using a JWT](https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-08) *(draft spec)*
- [OpenID Connect Token Bound Authentication](https://openid.net/specs/openid-connect-token-bound-authentication-1_0.html) *(draft spec; when combined with [mod_token_binding](https://github.com/zmartzone/mod_token_binding))*
- [OAuth 2.0 Token Binding for Authorization Codes for Web Server Clients](https://tools.ietf.org/html/draft-ietf-oauth-token-binding-07#section-5.2) *(draft spec)*
Alternatively the module can operate as an OAuth 2.0 Resource Server to an OAuth 2.0 Authorization Server,
validating bearer Access Tokens by introspecting them or verifying them locally if they are JWTs.
......@@ -50,6 +52,8 @@ In the OAuth 2.0 Resource Server mode *mod_auth_openidc* supports the following
- [RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750)
- [RFC 7662 - OAuth 2.0 Token Introspection](https://tools.ietf.org/html/rfc7662) (or similar)
- [RFC 8414 - OAuth 2.0 Authorization Server Metadata](https://tools.ietf.org/html/rfc8414)
- [OAuth 2.0 Token Binding for Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-token-binding-07#section-3) *(draft spec)*
- [OAuth 2.0 Mutual TLS Client Certificate Bound Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-mtls-12#section-3) *(draft spec)*
The `REMOTE_USER` variable setting, passing claims in HTTP headers and authorization based on `Require` primitives
works in the same way as described for OpenID Connect above. See the [Wiki](https://github.com/zmartzone/mod_auth_openidc/wiki/OAuth-2.0-Resource-Server) for information on how to configure it.
......@@ -60,6 +64,12 @@ in this directory. This file can also serve as an include file for `httpd.conf`.
Support
-------
#### Give back to mod_auth_openidc
Please consider giving back by sponsoring mod_auth_openidc development/maintenance/continuity and to express
your gratitude as a happy user or company.
See: https://www.patreon.com/mod_auth_openidc
Sponsored by: [Auth0](https://auth0.com) and [GLUU](https://www.gluu.org)
#### Community Support
For generic questions, see the Wiki pages with Frequently Asked Questions at:
[https://github.com/zmartzone/mod_auth_openidc/wiki](https://github.com/zmartzone/mod_auth_openidc/wiki)
......@@ -118,7 +128,7 @@ See also the [Wiki page on Keycloak](https://github.com/zmartzone/mod_auth_openi
```apache
OIDCProviderMetadataURL https://keycloak.example.net/auth/realms/master/.well-known/openid-configuration
# OIDCRedirectURI is a vanity URL that must point to a path protected by this module but must NOT point to any content
OIDCRedirectURI https://www.example.net/oauth2callback
OIDCRedirectURI https://www.example.net/example/oauth2callback
OIDCCryptoPassphrase random1234
OIDCClientID <your-client-id-registered-in-keycloak>
OIDCClientSecret <your-client-secret-registered-in-keycloak>
......
......@@ -92,6 +92,11 @@
# Used when OIDCProviderMetadataURL is not defined or the metadata obtained from that URL does not set it.
#OIDCProviderEndSessionEndpoint <url>
# Define whether the OP supports OpenID Connect Back Channel Logout.
# According to: https://openid.net/specs/openid-connect-backchannel-1_0.html
# Used when OIDCProviderMetadataURL is not defined or the metadata obtained from that URL does not set it.
#OIDCProviderBackChannelLogoutSupported [On|Off]
# Extra JSON parameters that need to be passed in the registration request to the Registration Endpoint.
# This settings serves as a default value for multiple OPs only.
# Parameter names and values need to be provided in JSON form and will be merged in to the request.
......@@ -394,6 +399,16 @@
# When not defined the default "header" is used.
#OIDCOAuthAcceptTokenAs [header|post|query|cookie[:<cookie-name>|basic]+
# The Token Binding policy used for OAuth 2.0 Access Tokens
# see: https://tools.ietf.org/html/draft-ietf-oauth-token-binding
# "disabled": no token binding ID will be verified in the access token, present or not
# "optional": the "cnf["tbh"]" claim is optional in the introspection result or the JWT access token, if it is present it will be verified
# "required": the "cnf["tbh"]" claim must be present when the Client supports Token Binding
# "enforced": the "cnf["tbh"]" claim must be present and the Client must support Token Binding
# When not defined the default is "optional".
#OIDCOAuthAccessTokenBindingPolicy [disabled|optional|required|enforced]
########################################################################################
#
# Cookie Settings
......@@ -447,6 +462,17 @@
# When not defined, no cookies are stripped.
#OIDCStripCookies [<cookie-name>]+
# Specify the maximum number of state cookies i.e. the maximum number of parallel outstanding
# authentication requests. See: https://github.com/zmartzone/mod_auth_openidc/issues/331
# Setting this to 0 means unlimited, until the browser or server gives up which is the
# behavior of mod_auth_openidc < 2.3.8, which did not have this configuration option.
#
# The optional second boolean parameter if the oldest state cookie(s) will be deleted,
# even if still valid; see #399.
#
# When not defined, the default is 7 and "false", thus the oldest cookie(s) will not be deleted.
#OIDCStateMaxNumberOfCookies <number> [false|true]
########################################################################################
#
# Session Settings (only relevant in an OpenID Connect Relying Party setup)
......@@ -764,3 +790,10 @@
# When not defined no claims are whitelisted and all claims are stored except when blacklisted with OIDCBlackListedClaims.
#OIDCWhiteListedClaims [<claim>]+
# Specify the minimum time-to-live for the access token stored in the OIDC session.
# When the access token expiry timestamp (or at tleast the hint given to that) is less than this value,
# an attempt will be made to refresh the access token using the refresh token grant type with the OP.
# This only has effect if a refresh token was actually returned from the OP and an "expires_in" hint
# was returned as part of the authorization response (and subsequent refresh token responses).
# When not defined no attempt is made to refresh the access token (unless implicitly with OIDCUserInfoRefreshInterval)
#OIDCRefreshAccessTokenBeforeExpiry <seconds>
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mod_auth_openidc 2.3.8.
# Generated by GNU Autoconf 2.69 for mod_auth_openidc 2.3.10.
#
# Report bugs to <hans.zandbelt@zmartzone.eu>.
#
......@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mod_auth_openidc'
PACKAGE_TARNAME='mod_auth_openidc'
PACKAGE_VERSION='2.3.8'
PACKAGE_STRING='mod_auth_openidc 2.3.8'
PACKAGE_VERSION='2.3.10'
PACKAGE_STRING='mod_auth_openidc 2.3.10'
PACKAGE_BUGREPORT='hans.zandbelt@zmartzone.eu'
PACKAGE_URL=''
......@@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mod_auth_openidc 2.3.8 to adapt to many kinds of systems.
\`configure' configures mod_auth_openidc 2.3.10 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
......@@ -1331,7 +1331,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mod_auth_openidc 2.3.8:";;
short | recursive ) echo "Configuration of mod_auth_openidc 2.3.10:";;
esac
cat <<\_ACEOF
......@@ -1445,7 +1445,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mod_auth_openidc configure 2.3.8
mod_auth_openidc configure 2.3.10
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
......@@ -1747,7 +1747,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mod_auth_openidc $as_me 2.3.8, which was
It was created by mod_auth_openidc $as_me 2.3.10, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
......@@ -2096,7 +2096,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
NAMEVER=mod_auth_openidc-2.3.8
NAMEVER=mod_auth_openidc-2.3.10
# This section defines the --with-apxs2 option.
......@@ -4886,7 +4886,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mod_auth_openidc $as_me 2.3.8, which was
This file was extended by mod_auth_openidc $as_me 2.3.10, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
......@@ -4939,7 +4939,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mod_auth_openidc config.status 2.3.8
mod_auth_openidc config.status 2.3.10
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
......
AC_INIT([mod_auth_openidc],[2.3.8],[hans.zandbelt@zmartzone.eu])
AC_INIT([mod_auth_openidc],[2.3.10],[hans.zandbelt@zmartzone.eu])
AC_SUBST(NAMEVER, AC_PACKAGE_TARNAME()-AC_PACKAGE_VERSION())
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -68,6 +68,8 @@ static apr_byte_t oidc_authz_match_value(request_rec *r, const char *spec_c,
int i = 0;
oidc_debug(r, "matching: spec_c=%s, key=%s", spec_c, key);
/* see if it is a string and it (case-insensitively) matches the Require'd value */
if (json_is_string(val)) {
......@@ -185,8 +187,8 @@ static apr_byte_t oidc_authz_match_expression(request_rec *r,
/*
* see if a the Require value matches with a set of provided claims
*/
apr_byte_t oidc_authz_match_claim(request_rec *r,
const char * const attr_spec, const json_t * const claims) {
apr_byte_t oidc_authz_match_claim(request_rec *r, const char * const attr_spec,
const json_t * const claims) {
const char *key;
json_t *val;
......@@ -237,14 +239,25 @@ apr_byte_t oidc_authz_match_claim(request_rec *r,
/* skip the dot */
spec_c++;
if (!json_is_object(val)) {
oidc_warn(r, "\"%s\" matched, and child nodes should be evaluated, but value is not an object.", key);
if (json_is_object(val)) {
oidc_debug(r,
"attribute chunk matched, evaluating children of key: \"%s\".",
key);
return oidc_authz_match_claim(r, spec_c,
json_object_get(claims, key));
} else if (json_is_array(val)) {
oidc_debug(r,
"attribute chunk matched, evaluating array values of key: \"%s\".",
key);
return oidc_authz_match_value(r, spec_c,
json_object_get(claims, key), key);
} else {
oidc_warn(r,
"\"%s\" matched, and child nodes or array values should be evaluated, but value is not an object or array.",
key);
return FALSE;
}
oidc_debug(r, "Attribute chunk matched. Evaluating children of key: \"%s\".", key);
return oidc_authz_match_claim(r, spec_c, json_object_get(claims, key));
}
iter = json_object_iter_next((json_t *) claims, iter);
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -106,6 +106,10 @@ apr_byte_t oidc_cache_set(request_rec *r, const char *section, const char *key,
#define OIDC_CACHE_SECTION_OAUTH_PROVIDER "o"
#define OIDC_CACHE_SECTION_JTI "t"
#define OIDC_CACHE_SECTION_REQUEST_URI "r"
#define OIDC_CACHE_SECTION_SID "d"
// TODO: now every section occupies the same space; we may want to differentiate
// according to section-based size, at least for the shm backend
#define oidc_cache_get_session(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_SESSION, key, value)
#define oidc_cache_get_nonce(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_NONCE, key, value)
......@@ -115,6 +119,7 @@ apr_byte_t oidc_cache_set(request_rec *r, const char *section, const char *key,
#define oidc_cache_get_oauth_provider(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_OAUTH_PROVIDER, key, value)
#define oidc_cache_get_jti(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_JTI, key, value)
#define oidc_cache_get_request_uri(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_REQUEST_URI, key, value)
#define oidc_cache_get_sid(r, key, value) oidc_cache_get(r, OIDC_CACHE_SECTION_SID, key, value)
#define oidc_cache_set_session(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_SESSION, key, value, expiry)
#define oidc_cache_set_nonce(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_NONCE, key, value, expiry)
......@@ -124,6 +129,7 @@ apr_byte_t oidc_cache_set(request_rec *r, const char *section, const char *key,
#define oidc_cache_set_oauth_provider(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_OAUTH_PROVIDER, key, value, expiry)
#define oidc_cache_set_jti(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_JTI, key, value, expiry)
#define oidc_cache_set_request_uri(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_REQUEST_URI, key, value, expiry)
#define oidc_cache_set_sid(r, key, value, expiry) oidc_cache_set(r, OIDC_CACHE_SECTION_SID, key, value, expiry)
extern oidc_cache_t oidc_cache_file;
extern oidc_cache_t oidc_cache_memcache;
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -437,17 +437,18 @@ static int oidc_cache_crypto_encrypt(request_rec *r, const char *plaintext,
if (encoded_len > 0) {
p = encoded;
/* base64url encode the tag */
e_tag_len = oidc_base64url_encode(r, &e_tag, (const char *) tag,
OIDC_CACHE_TAG_LEN, 1);
/* now allocated space for the concatenated base64url encoded ciphertext and tag */
encoded = apr_pcalloc(r->pool,
encoded_len + 1 + OIDC_CACHE_TAG_LEN + 1);
encoded = apr_pcalloc(r->pool, encoded_len + 1 + e_tag_len + 1);
memcpy(encoded, p, encoded_len);
p = encoded + encoded_len;
*p = OIDC_CHAR_DOT;
p++;
/* base64url encode the tag and append it in the buffer */
e_tag_len = oidc_base64url_encode(r, &e_tag, (const char *) tag,
OIDC_CACHE_TAG_LEN, 1);
/* append the tag in the buffer */
memcpy(p, e_tag, e_tag_len);
encoded_len += e_tag_len + 1;
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......
This diff is collapsed.
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -369,7 +369,7 @@ apr_byte_t oidc_jwk_to_json(apr_pool_t *pool, oidc_jwk_t *jwk, char **s_json,
/*
* hash a sequence of bytes with a specific algorithm and return the result as a base64url-encoded \0 terminated string
*/
static apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool,
apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool,
const char *openssl_hash_algo, const char *input, int input_len,
char **output) {
oidc_jose_error_t err;
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -117,6 +117,9 @@ apr_byte_t oidc_jose_hash_bytes(apr_pool_t *pool, const char *s_digest,
const unsigned char *input, unsigned int input_len,
unsigned char **output, unsigned int *output_len,
oidc_jose_error_t *err);
apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool,
const char *openssl_hash_algo, const char *input, int input_len,
char **output);
/* return a string claim value from a JSON object */
apr_byte_t oidc_jose_get_string(apr_pool_t *pool, json_t *json,
......
This diff is collapsed.
This diff is collapsed.
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -73,6 +73,8 @@ APLOG_USE_MODULE(auth_openidc);
#define oidc_log(r, level, fmt, ...) ap_log_rerror(APLOG_MARK, level, 0, r,"%s: %s", __FUNCTION__, apr_psprintf(r->pool, fmt, ##__VA_ARGS__))
#define oidc_slog(s, level, fmt, ...) ap_log_error(APLOG_MARK, level, 0, s, "%s: %s", __FUNCTION__, apr_psprintf(s->process->pool, fmt, ##__VA_ARGS__))
//#define oidc_log(r, level, fmt, ...) fprintf(stderr, "# %s: %s\n", __FUNCTION__, apr_psprintf(r->pool, fmt, ##__VA_ARGS__))
//#define oidc_slog(s, level, fmt, ...) fprintf(stderr, "## %s: %s\n", __FUNCTION__, apr_psprintf(s->process->pool, fmt, ##__VA_ARGS__))
#define oidc_debug(r, fmt, ...) oidc_log(r, OIDC_DEBUG, fmt, ##__VA_ARGS__)
#define oidc_warn(r, fmt, ...) oidc_log(r, APLOG_WARNING, fmt, ##__VA_ARGS__)
......@@ -186,6 +188,7 @@ APLOG_USE_MODULE(auth_openidc);
/* define the parameter value for the "logout" request that indicates a GET-style logout call from the OP */
#define OIDC_GET_STYLE_LOGOUT_PARAM_VALUE "get"
#define OIDC_IMG_STYLE_LOGOUT_PARAM_VALUE "img"
#define OIDC_BACKCHANNEL_STYLE_LOGOUT_PARAM_VALUE "backchannel"
/* define the name of the cookie/parameter for CSRF protection */
#define OIDC_CSRF_NAME "x_csrf"
......@@ -216,6 +219,8 @@ APLOG_USE_MODULE(auth_openidc);
/* https://tools.ietf.org/html/draft-ietf-tokbind-ttrp-01 */
#define OIDC_TB_CFG_PROVIDED_ENV_VAR "Sec-Provided-Token-Binding-ID"
/* https://www.ietf.org/id/draft-ietf-oauth-mtls-12 */
#define OIDC_TB_CFG_FINGERPRINT_ENV_VAR "TB_SSL_CLIENT_CERT_FINGERPRINT"
#define OIDC_TOKEN_BINDING_POLICY_DISABLED 0
#define OIDC_TOKEN_BINDING_POLICY_OPTIONAL 1
......@@ -259,6 +264,7 @@ typedef struct oidc_provider_t {
char *client_secret;
char *token_endpoint_tls_client_key;
char *token_endpoint_tls_client_cert;
int backchannel_logout_supported;
// the next ones function as global default settings too
int ssl_validate_server;
......@@ -317,6 +323,7 @@ typedef struct oidc_oauth_t {
apr_hash_t *verify_shared_keys;
char *verify_jwks_uri;
apr_hash_t *verify_public_keys;
int access_token_binding_policy;
} oidc_oauth_t;
typedef struct oidc_cfg {
......@@ -380,6 +387,7 @@ typedef struct oidc_cfg {
int http_timeout_short;
int state_timeout;
int max_number_of_state_cookies;
int delete_oldest_state_cookies;
int session_inactivity_timeout;
int session_cache_fallback_to_cookie;
......@@ -464,6 +472,7 @@ apr_byte_t oidc_oauth_get_bearer_token(request_rec *r, const char **access_token
#define OIDC_PROTO_REQUEST_OBJECT "request"
#define OIDC_PROTO_SESSION_STATE "session_state"
#define OIDC_PROTO_ACTIVE "active"
#define OIDC_PROTO_LOGOUT_TOKEN "logout_token"
#define OIDC_PROTO_RESPONSE_TYPE_CODE "code"
#define OIDC_PROTO_RESPONSE_TYPE_IDTOKEN "id_token"
......@@ -513,6 +522,11 @@ apr_byte_t oidc_oauth_get_bearer_token(request_rec *r, const char **access_token
#define OIDC_CLAIM_C_HASH "c_hash"
#define OIDC_CLAIM_RFP "rfp"
#define OIDC_CLAIM_TARGET_LINK_URI "target_link_uri"
#define OIDC_CLAIM_CNF "cnf"
#define OIDC_CLAIM_CNF_TBH "tbh"
#define OIDC_CLAIM_CNF_X5T_S256 "x5t#S256"
#define OIDC_CLAIM_SID "sid"
#define OIDC_CLAIM_EVENTS "events"
#define OIDC_JWK_X5T "x5t"
#define OIDC_JWK_KEYS "keys"
......@@ -617,8 +631,9 @@ apr_array_header_t *oidc_proto_supported_flows(apr_pool_t *pool);
apr_byte_t oidc_proto_flow_is_supported(apr_pool_t *pool, const char *flow);
apr_byte_t oidc_proto_validate_authorization_response(request_rec *r, const char *response_type, const char *requested_response_mode, char **code, char **id_token, char **access_token, char **token_type, const char *used_response_mode);
apr_byte_t oidc_proto_jwt_verify(request_rec *r, oidc_cfg *cfg, oidc_jwt_t *jwt, const oidc_jwks_uri_t *jwks_uri, apr_hash_t *symmetric_keys);
apr_byte_t oidc_proto_validate_jwt(request_rec *r, oidc_jwt_t *jwt, const char *iss, apr_byte_t exp_is_mandatory, apr_byte_t iat_is_mandatory, int iat_slack);
apr_byte_t oidc_proto_validate_jwt(request_rec *r, oidc_jwt_t *jwt, const char *iss, apr_byte_t exp_is_mandatory, apr_byte_t iat_is_mandatory, int iat_slack, int token_binding_policy);
apr_byte_t oidc_proto_generate_nonce(request_rec *r, char **nonce, int len);
apr_byte_t oidc_proto_validate_aud_and_azp(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, oidc_jwt_payload_t *id_token_payload);
apr_byte_t oidc_proto_authorization_response_code_idtoken_token(request_rec *r, oidc_cfg *c, oidc_proto_state_t *proto_state, oidc_provider_t *provider, apr_table_t *params, const char *response_mode, oidc_jwt_t **jwt);
apr_byte_t oidc_proto_authorization_response_code_idtoken(request_rec *r, oidc_cfg *c, oidc_proto_state_t *proto_state, oidc_provider_t *provider, apr_table_t *params, const char *response_mode, oidc_jwt_t **jwt);
......@@ -691,6 +706,8 @@ int oidc_cfg_session_cache_fallback_to_cookie(request_rec *r);
const char *oidc_parse_pkce_type(apr_pool_t *pool, const char *arg, oidc_proto_pkce_t **type);
const char *oidc_cfg_claim_prefix(request_rec *r);
int oidc_cfg_max_number_of_state_cookies(oidc_cfg *cfg);
int oidc_cfg_dir_refresh_access_token_before_expiry(request_rec *r);
int oidc_cfg_delete_oldest_state_cookies(oidc_cfg *cfg);
// oidc_util.c
int oidc_strnenvcmp(const char *a, const char *b, int len);
......@@ -791,6 +808,7 @@ void oidc_util_hdr_out_location_set(const request_rec *r, const char *value);
const char *oidc_util_hdr_out_location_get(const request_rec *r);
void oidc_util_hdr_err_out_add(const request_rec *r, const char *name, const char *value);
apr_byte_t oidc_util_hdr_in_accept_contains(const request_rec *r, const char *needle);
apr_byte_t oidc_util_json_validate_cnf(request_rec *r, json_t *jwt, int token_binding_policy);
// oidc_metadata.c
apr_byte_t oidc_metadata_provider_retrieve(request_rec *r, oidc_cfg *cfg, const char *issuer, const char *url, json_t **j_metadata, char **response);
......@@ -807,6 +825,7 @@ typedef struct {
const char *remote_user; /* user who owns this particular session */
json_t *state; /* the state for this session, encoded in a JSON object */
apr_time_t expiry; /* if > 0, the time of expiry of this session */
const char *sid;
} oidc_session_t;
apr_byte_t oidc_session_load(request_rec *r, oidc_session_t **z);
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -480,6 +480,11 @@ static apr_byte_t oidc_oauth_resolve_access_token(request_rec *r, oidc_cfg *c,
if (oidc_util_decode_json_and_check_error(r, s_json, &result) == FALSE)
return FALSE;
/* check the token binding ID in the introspection result */
if (oidc_util_json_validate_cnf(r, result,
c->oauth.access_token_binding_policy) == FALSE)
return FALSE;
json_t *active = json_object_get(result, OIDC_PROTO_ACTIVE);
apr_time_t cache_until;
if (active != NULL) {
......@@ -580,7 +585,7 @@ static apr_byte_t oidc_oauth_resolve_access_token(request_rec *r, oidc_cfg *c,
*
* TODO: document that we're reusing the following settings from the OIDC config section:
* - JWKs URI refresh interval
* - encryption key material (OIDCPrivateKeyFiles)
* - decryption key material (OIDCPrivateKeyFiles)
*
* OIDCOAuthRemoteUserClaim client_id
* # 32x 61 hex
......@@ -594,6 +599,8 @@ static apr_byte_t oidc_oauth_validate_jwt_access_token(request_rec *r,
oidc_jose_error_t err;
oidc_jwk_t *jwk = NULL;
// TODO: replace this OIDC client secret with OIDCOAuthDecryptSharedKeys
if (oidc_util_create_symmetric_key(r, c->provider.client_secret, 0, NULL,
TRUE, &jwk) == FALSE)
return FALSE;
......@@ -615,7 +622,8 @@ static apr_byte_t oidc_oauth_validate_jwt_access_token(request_rec *r,
* validate the access token JWT by validating the (optional) exp claim
* don't enforce anything around iat since it doesn't make much sense for access tokens
*/
if (oidc_proto_validate_jwt(r, jwt, NULL, FALSE, FALSE, -1) == FALSE) {
if (oidc_proto_validate_jwt(r, jwt, NULL, FALSE, FALSE, -1,
c->oauth.access_token_binding_policy) == FALSE) {
oidc_jwt_destroy(jwt);
return FALSE;
}
......@@ -705,7 +713,8 @@ static apr_byte_t oidc_oauth_set_request_user(request_rec *r, oidc_cfg *c,
/*
* main routine: handle OAuth 2.0 authentication/authorization
*/
int oidc_oauth_check_userid(request_rec *r, oidc_cfg *c, const char *access_token) {
int oidc_oauth_check_userid(request_rec *r, oidc_cfg *c,
const char *access_token) {
/* check if this is a sub-request or an initial request */
if (!ap_is_initial_req(r)) {
......@@ -753,7 +762,8 @@ int oidc_oauth_check_userid(request_rec *r, oidc_cfg *c, const char *access_toke
return OK;
}
return oidc_oauth_return_www_authenticate(r,
OIDC_PROTO_ERR_INVALID_REQUEST, "No bearer token found in the request");
OIDC_PROTO_ERR_INVALID_REQUEST,
"No bearer token found in the request");
}
}
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -551,7 +551,6 @@ const char *oidc_valid_max_number_of_state_cookies(apr_pool_t *pool, int v) {
return NULL;
}
/*
* parse a session max duration value from the provided string
*/
......@@ -564,8 +563,8 @@ const char *oidc_parse_session_max_duration(apr_pool_t *pool, const char *arg,
/*
* parse a base64 encoded binary value from the provided string
*/
char *oidc_parse_base64(apr_pool_t *pool, const char *input,
char **output, int *output_len) {
char *oidc_parse_base64(apr_pool_t *pool, const char *input, char **output,
int *output_len) {
int len = apr_base64_decode_len(input);
*output = apr_palloc(pool, len);
*output_len = apr_base64_decode(*output, input);
......@@ -858,8 +857,6 @@ const char *oidc_parse_accept_oauth_token_in(apr_pool_t *pool, const char *arg,
} else {
p = OIDC_OAUTH_ACCEPT_TOKEN_IN_COOKIE_NAME_DEFAULT;
}
apr_hash_set(list_options, OIDC_OAUTH_ACCEPT_TOKEN_IN_OPTION_COOKIE_NAME,
APR_HASH_KEY_STRING, p);
rv = oidc_valid_string_option(pool, s, options);
if (rv != NULL)
......@@ -871,6 +868,12 @@ const char *oidc_parse_accept_oauth_token_in(apr_pool_t *pool, const char *arg,
else
*b_value |= v;
if (v == OIDC_OAUTH_ACCEPT_TOKEN_IN_COOKIE) {
apr_hash_set(list_options,
OIDC_OAUTH_ACCEPT_TOKEN_IN_OPTION_COOKIE_NAME,
APR_HASH_KEY_STRING, p);
}
return NULL;
}
......@@ -1245,7 +1248,34 @@ const char *oidc_parse_auth_request_method(apr_pool_t *pool, const char *arg,
* parse the maximum number of parallel state cookies
*/
const char *oidc_parse_max_number_of_state_cookies(apr_pool_t *pool,
const char *arg1, const char *arg2, int *int_value, int *bool_value) {
const char *rv = NULL;
rv = oidc_parse_int_valid(pool, arg1, int_value,
oidc_valid_max_number_of_state_cookies);
if ((rv == NULL) && (arg2 != NULL))
rv = oidc_parse_boolean(pool, arg2, bool_value);
return rv;
}
#define OIDC_REFRESH_ACCESS_TOKEN_BEFORE_EXPIRY_MIN 0
#define OIDC_REFRESH_ACCESS_TOKEN_BEFORE_EXPIRY_MAX 3600 * 24 * 365
/*
* check the boundaries for the refresh access token expiry TTL
*/
const char *oidc_valid_refresh_access_token_before_expiry(apr_pool_t *pool,
int v) {
return oidc_valid_int_min_max(pool, v,
OIDC_REFRESH_ACCESS_TOKEN_BEFORE_EXPIRY_MIN,
OIDC_REFRESH_ACCESS_TOKEN_BEFORE_EXPIRY_MAX);
}
/*
* parse an access token expiry TTL from the provided string
*/
const char *oidc_parse_refresh_access_token_before_expiry(apr_pool_t *pool,
const char *arg, int *int_value) {
return oidc_parse_int_valid(pool, arg, int_value,
oidc_valid_max_number_of_state_cookies);
oidc_valid_refresh_access_token_before_expiry);
}
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -117,7 +117,8 @@ const char *oidc_parse_info_hook_data(apr_pool_t *pool, const char *arg, apr_has
const char *oidc_parse_token_binding_policy(apr_pool_t *pool, const char *arg, int *int_value);
const char *oidc_token_binding_policy2str(apr_pool_t *pool, int v);
const char *oidc_parse_auth_request_method(apr_pool_t *pool, const char *arg, int *method);
const char *oidc_parse_max_number_of_state_cookies(apr_pool_t *pool, const char *arg, int *int_value);
const char *oidc_parse_max_number_of_state_cookies(apr_pool_t *pool, const char *arg1, const char *arg2, int *int_value, int *bool_value);
const char *oidc_parse_refresh_access_token_before_expiry(apr_pool_t *pool, const char *arg, int *int_value);
typedef const char *(*oidc_valid_int_function_t)(apr_pool_t *, int);
typedef const char *(*oidc_valid_function_t)(apr_pool_t *, const char *);
......
......@@ -18,7 +18,7 @@
*/
/***************************************************************************
* Copyright (C) 2017-2018 ZmartZone IAM
* Copyright (C) 2017-2019 ZmartZone IAM
* Copyright (C) 2013-2017 Ping Identity Corporation
* All rights reserved.
*
......@@ -1054,7 +1054,7 @@ apr_byte_t oidc_proto_validate_nonce(request_rec *r, oidc_cfg *cfg,
/*
* validate the "aud" and "azp" claims in the id_token payload
*/
static apr_byte_t oidc_proto_validate_aud_and_azp(request_rec *r, oidc_cfg *cfg,
apr_byte_t oidc_proto_validate_aud_and_azp(request_rec *r, oidc_cfg *cfg,
oidc_provider_t *provider, oidc_jwt_payload_t *id_token_payload) {
char *azp = NULL;
......@@ -1123,101 +1123,6 @@ static apr_byte_t oidc_proto_validate_aud_and_azp(request_rec *r, oidc_cfg *cfg,
return TRUE;
}