Commit ab32b14d authored by godog's avatar godog

Merge branch 'apache24'

parents 66f6744f cb308bf6
......@@ -5,7 +5,7 @@ AC_LANG(C++)
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
AC_CONFIG_HEADERS(src/sso/config.h)
AC_CONFIG_MACRO_DIR([m4])
AC_DISABLE_SHARED
dnl AC_DISABLE_SHARED
dnl Program checks.
AC_PROG_CC
......@@ -39,27 +39,12 @@ dnl Checks for apxs.
if test "$build_mod_sso" != "no" ; then
AX_WITH_APXS()
APACHE_CFLAGS="-I`${APXS} -q INCLUDEDIR`"
AC_ARG_WITH(apr_config,
AC_HELP_STRING([[--with-apr-config=FILE]],
[Path to apr-config program]),
[ apr_config="$withval" ],
[AC_PATH_PROGS(apr_config,
[apr-config apr-0-config apr-1-config],
[no],
[$PATH:/usr/sbin/:/usr/local/apache2/bin]
)]
)
if test "$apr_config" != "no" ; then
AC_MSG_CHECKING('APR includes')
APACHE_CFLAGS="$APACHE_CFLAGS -I`${apr_config} --includedir`"
AC_MSG_RESULT($APACHE_CFLAGS)
AC_MSG_CHECKING('APR libs')
APR_LIBS="`${apr_config} --link-libtool --libs`"
AC_MSG_RESULT($APR_LIBS)
fi
AC_SUBST(APACHE_CFLAGS)
APACHE_LIBEXEC_DIR="`${APXS} -q LIBEXECDIR`"
AC_SUBST(APACHE_LIBEXEC_DIR)
PKG_CHECK_MODULES(APR, [apr-1, apr-util-1])
AC_SUBST(APR_CFLAGS)
AC_SUBST(APR_LIBS)
fi
AM_CONDITIONAL(ENABLE_MOD_SSO, [ test "$build_mod_sso" != "no" ])
......
......@@ -4,7 +4,8 @@ Priority: extra
Maintainer: Autistici/Inventati <debian@autistici.org>
Build-Depends: debhelper (>= 5), apache2-prefork-dev | apache2-threaded-dev,
autoconf, automake, libtool, python-dev, python-support, swig,
libpam-dev, python-setuptools
libpam-dev, python-setuptools, python-flup, pkg-config, libz-dev,
python-werkzeug, python-mox, python-flask, python-nose, apache2-bin | apache2
Standards-Version: 3.7.2
Package: ai-sso
......
......@@ -8,7 +8,7 @@ noinst_DATA = mod_sso.la
SSO_LIBS = $(top_builddir)/src/sso/libsso.la
libmod_sso_la_SOURCES = mod_sso.c mod_sso.h sso_utils.c
libmod_sso_la_CPPFLAGS = $(APACHE_CFLAGS) $(AM_CPPFLAGS)
libmod_sso_la_CPPFLAGS = $(APACHE_CFLAGS) $(APR_CFLAGS) $(AM_CPPFLAGS)
libmod_sso_la_LDFLAGS = -module
libmod_sso_la_LIBADD = $(SSO_LIBS)
......
......@@ -37,6 +37,11 @@
#include "mod_sso.h"
#if MODULE_MAGIC_NUMBER_MAJOR >= 20100714
#define SSO_REQUIRE_NAME "sso"
#include "mod_auth.h"
#endif
extern module AP_MODULE_DECLARE_DATA sso_module;
typedef struct {
......@@ -46,10 +51,27 @@ typedef struct {
// Note: public_key is a binary buffer (non zero-terminated).
const unsigned char *public_key;
// All known groups (2.4: unused).
apr_array_header_t *groups;
} modsso_config;
typedef const char *(*CMD_HAND_TYPE) ();
static char *groups_array_to_commasep_string(apr_pool_t *p, apr_array_header_t *groups)
{
return apr_array_pstrcat(p, groups, ',');
}
static char *groups_charp_to_string(apr_pool_t *p, const char **groups) {
apr_array_header_t *arr = apr_array_make(p, 1, sizeof(char *));
const char **gptr;
for (gptr = groups; *gptr; gptr++) {
*(const char **)apr_array_push(arr) = *gptr;
}
return groups_array_to_commasep_string(p, arr);
}
/**
* Create a modsso_config structure.
*
......@@ -70,7 +92,8 @@ static void *create_modsso_config(apr_pool_t *p, char *s)
newcfg->service = NULL;
newcfg->domain = NULL;
newcfg->public_key = NULL;
newcfg->groups = NULL;
// Return the created configuration struct.
return (void *)newcfg;
}
......@@ -85,11 +108,13 @@ static void *merge_modsso_config(apr_pool_t *p, void *base, void *add)
newcfg->login_server = cadd->login_server ? cadd->login_server : cbase->login_server;
newcfg->service = cadd->service ? cadd->service : cbase->service;
newcfg->domain = cadd->domain ? cadd->domain : cbase->domain;
newcfg->public_key = cbase->public_key;
if (cadd->public_key) {
newcfg->public_key = cadd->public_key;
}
}
// Groups are not merged, last takes precedence (if set).
newcfg->groups = cadd->groups ? cadd->groups : cbase->groups;
return (void *)newcfg;
}
......@@ -393,11 +418,16 @@ static int mod_sso_method_handler(request_rec *r)
// Return immediately if there's nothing to do (check the AuthType)
type = ap_auth_type(r);
if (!type || strcasecmp(type, "SSO") != 0) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: invalid authentication type \"%s\"", type);
return DECLINED;
}
sso_cookie_name = get_cookie_name(r);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: cookie_name \"%s\"", sso_cookie_name);
// Check if the required parameters are defined.
if (!check_config(r, s_cfg)) {
return HTTP_INTERNAL_SERVER_ERROR;
......@@ -406,13 +436,15 @@ static int mod_sso_method_handler(request_rec *r)
// Parse the service into host/path (guess it if not specified).
if (parse_service(r, s_cfg, &service, &service_host, &service_path) != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"sso: could not parse service \"%s\"",
s_cfg->service);
"sso: could not parse service \"%s\"",
s_cfg->service);
return HTTP_BAD_REQUEST;
}
// Handle /sso_logout
sso_logout_path = apr_pstrcat(r->pool, service_path, "sso_logout", NULL);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: logout? \"%s\" \"%s\"", sso_logout_path, uri);
if (!strcmp(uri, sso_logout_path)) {
modsso_del_cookie(r, sso_cookie_name);
return http_sendstring(r, "OK");
......@@ -420,6 +452,8 @@ static int mod_sso_method_handler(request_rec *r)
// Handle /sso_login
sso_login_path = apr_pstrcat(r->pool, service_path, "sso_login", NULL);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: login? \"%s\" \"%s\"", sso_login_path, uri);
if (!strcmp(uri, sso_login_path)) {
struct modsso_params params;
char *redir;
......@@ -453,6 +487,7 @@ static int mod_sso_method_handler(request_rec *r)
return DECLINED;
}
#if MODULE_MAGIC_NUMBER_MAJOR < 20100714
struct modsso_auth_req {
apr_array_header_t *groups;
apr_array_header_t *users;
......@@ -536,27 +571,13 @@ static void mod_sso_parse_requirements(request_rec *r,
*(const char **)apr_array_push(auth->groups) = NULL;
}
}
static char *encode_groups(apr_pool_t *p, apr_array_header_t *groups)
{
apr_array_header_t *arr = apr_array_make(p, (groups->nelts - 1) * 2 - 1, sizeof(const char *));
int i;
/* Create a temporary array with strings and commas. */
for (i = 0; i < groups->nelts - 1; i++) {
if (i > 0) {
*(const char **)apr_array_push(arr) = ",";
}
*(const char **)apr_array_push(arr) = ((const char **)groups->elts)[i];
}
return apr_array_pstrcat(p, arr, 0);
}
#endif
static int redirect_to_login_server(request_rec *r,
const char *login_server,
const char *service_host,
const char *service,
apr_array_header_t *groups)
const char **groups)
{
char *dest, *login_url;
dest = full_uri(r, service_host);
......@@ -567,18 +588,21 @@ static int redirect_to_login_server(request_rec *r,
"&d=",
modsso_url_encode(r->pool, dest),
NULL);
if (!apr_is_empty_array(groups)) {
if (groups) {
login_url = apr_pstrcat(r->pool,
login_url,
"&g=",
encode_groups(r->pool, groups),
groups_charp_to_string(r->pool, groups),
NULL);
}
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
"sso: unauthorized access to %s", dest);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: redirecting to %s", login_url);
return http_redirect(r, login_url);
}
#if MODULE_MAGIC_NUMBER_MAJOR < 20100714
static char *pkey_to_string(const unsigned char *pkey, char *buf) {
static const char *hex = "0123456789ABCDEF";
char *o = buf;
......@@ -591,13 +615,151 @@ static char *pkey_to_string(const unsigned char *pkey, char *buf) {
*o = '\0';
return buf;
}
#endif
/**
* Apache authentication handler for mod_sso.
*
* @param r Pointer to the request_rec structure.
*/
static int mod_sso_authenticate_user(request_rec *r)
#if MODULE_MAGIC_NUMBER_MAJOR >= 20100714
static int mod_sso_check_access_ex(request_rec *r)
{
const char *type, *uri;
const char *sso_login_path, *sso_logout_path;
const char *service = NULL, *service_host = NULL,
*service_path = NULL;
modsso_config *s_cfg = (modsso_config *)
ap_get_module_config(r->per_dir_config, &sso_module);
type = ap_auth_type(r);
if (type == NULL || apr_strnatcasecmp(type, "sso") != 0) {
return DECLINED;
}
// Check if the required parameters are defined.
if (!check_config(r, s_cfg)) {
return HTTP_INTERNAL_SERVER_ERROR;
}
uri = r->uri;
if (parse_service(r, s_cfg, &service, &service_host, &service_path) != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"sso (check_access_ex): could not parse service (cfg->service=%s)",
s_cfg->service);
return HTTP_BAD_REQUEST;
}
// Everyone is allowed access to /sso_login and /sso_logout
sso_logout_path = apr_pstrcat(r->pool, service_path, "sso_logout", NULL);
sso_login_path = apr_pstrcat(r->pool, service_path, "sso_login", NULL);
if (!strcmp(uri, sso_logout_path) || !strcmp(uri, sso_login_path)) {
return OK;
}
return DECLINED;
}
static int mod_sso_check_user_id(request_rec *r)
{
const char *type, *sso_cookie_name, *sso_cookie;
const char *service = NULL, *service_host = NULL,
*service_path = NULL;
int retval, err, do_redirect = 1;
const char **required_groups;
modsso_config *s_cfg = (modsso_config *)
ap_get_module_config(r->per_dir_config, &sso_module);
//apr_array_header_t *sso_validate_groups = NULL;
type = ap_auth_type(r);
if (type == NULL || apr_strnatcasecmp(type, "sso") != 0) {
return DECLINED;
}
// If this is a sub-request, pass existing credentials, if any.
if (!ap_is_initial_req(r)) {
if (r->main != NULL) {
r->user = r->main->user;
} else if (r->prev != NULL) {
r->user = r->prev->user;
}
if (r->user != NULL) {
return OK;
}
}
sso_cookie_name = get_cookie_name(r);
// Check if the required parameters are defined.
if (!check_config(r, s_cfg)) {
return HTTP_INTERNAL_SERVER_ERROR;
}
if (parse_service(r, s_cfg, &service, &service_host, &service_path) != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"sso (check_user_id): could not parse service (cfg->service=%s)",
s_cfg->service);
return HTTP_BAD_REQUEST;
}
// Fetch the list of desired groups set (eventually) by group_check_authorization.
required_groups = (const char **)apr_table_get(r->notes, "SSO_REQUIRED_GROUPS");
// Test for valid cookie
sso_cookie = get_cookie(r, sso_cookie_name);
if (sso_cookie != NULL) {
sso_ticket_t t;
#if 0
// Print some debugging information about the service
{
char pkeybuf[512];
const char *host_hdr = apr_table_get(r->headers_in, "Host");
if (!host_hdr) {
host_hdr = "null";
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso request: uri=%s, service=%s, orig=%s, host=%s, tkt=%s, pkey=%s",
r->uri, service, s_cfg->service, host_hdr, sso_cookie,
pkey_to_string(s_cfg->public_key, pkeybuf));
}
#endif
err = sso_ticket_open(&t, sso_cookie, s_cfg->public_key);
if (err != SSO_OK) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"sso: ticket decoding error: %s", sso_strerror(err));
} else {
err = sso_validate(t, s_cfg->service, s_cfg->domain, required_groups);
if (err != SSO_OK) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"sso: validation error: %s", sso_strerror(err));
} else {
// Don't do this: t->groups wil be freed by sso_ticket_free
// apr_table_setn(r->notes, "SSO_GROUPS", (char *)(t->groups));
apr_table_setn(r->subprocess_env, "SSO_SERVICE",
apr_pstrdup(r->pool, service));
r->user = apr_pstrdup(r->pool, t->user);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"sso: authorized user '%s'",
r->user);
retval = OK;
do_redirect = 0;
}
sso_ticket_free(t);
}
}
if (!do_redirect) {
return retval;
}
// Redirect to login server
return redirect_to_login_server(r, s_cfg->login_server, service_host, service, required_groups);
}
#else
static int mod_sso_check_user_id(request_rec *r)
{
const char *type, *sso_cookie_name, *sso_cookie, *uri;
const char *sso_login_path, *sso_logout_path;
......@@ -609,10 +771,22 @@ static int mod_sso_authenticate_user(request_rec *r)
ap_get_module_config(r->per_dir_config, &sso_module);
type = ap_auth_type(r);
if (!type || strcasecmp(type, "SSO") != 0) {
if (type == NULL || apr_strnatcasecmp(type, "sso") != 0) {
return DECLINED;
}
// If this is a sub-request, pass existing credentials, if any.
if (!ap_is_initial_req(r)) {
if (r->main != NULL) {
r->user = r->main->user;
} else if (r->prev != NULL) {
r->user = r->prev->user;
}
if (r->user != NULL) {
return OK;
}
}
sso_cookie_name = get_cookie_name(r);
// Check if the required parameters are defined.
......@@ -624,7 +798,7 @@ static int mod_sso_authenticate_user(request_rec *r)
if (parse_service(r, s_cfg, &service, &service_host, &service_path) != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"sso (authenticate_user): could not parse service (cfg->service=%s)",
"sso (check_user_id): could not parse service (cfg->service=%s)",
s_cfg->service);
return HTTP_BAD_REQUEST;
}
......@@ -693,12 +867,91 @@ static int mod_sso_authenticate_user(request_rec *r)
}
// Redirect to login server
return redirect_to_login_server(r, s_cfg->login_server, service_host, service, auth.groups);
return redirect_to_login_server(r, s_cfg->login_server, service_host, service, apr_is_empty_array(auth.groups) ? NULL : (const char **)auth.groups->elts);
}
#endif /* apache 2.2 */
/**
* Apache authorization check callback for mod_sso.
*/
#if MODULE_MAGIC_NUMBER_MAJOR >= 20100714
static char **groups_array_to_charpp(apr_pool_t *p, apr_array_header_t *groups) {
int i;
char **pp, **ptr;
pp = (char **)apr_palloc(p, sizeof(char *) * (groups->nelts + 1));
for (ptr = pp, i = 0; i < groups->nelts; i++) {
*ptr++ = APR_ARRAY_IDX(groups, i, char *);
}
*ptr = NULL;
return pp;
}
static apr_array_header_t *required_groups_array(request_rec *r, const void *parsed_require_args) {
const ap_expr_info_t *expr = parsed_require_args;
const char *err = NULL;
const char *require, *w, *t;
apr_array_header_t *grouparr = apr_array_make(r->pool, 1, sizeof(char *));
require = ap_expr_str_exec(r, expr, &err);
if (err) {
return NULL;
}
t = require;
while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
*(const char **)apr_array_push(grouparr) = w;
}
return grouparr;
}
static char **required_groups_charpp(request_rec *r, const void *parsed_require_args) {
apr_array_header_t *arr = required_groups_array(r, parsed_require_args);
if (!arr) {
return NULL;
}
return groups_array_to_charpp(r->pool, arr);
}
// This function will be called twice: first, before any authn
// handlers are executed, and we return AUTHZ_DENIED_NO_USER to tell
// Apache that we need a user. This should cause it to invoke
// mod_sso_check_user_id, and then call this function again.
static authz_status group_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args) {
// Do we have a user? All ok then! We assume that the request was
// validated by mod_sso_check_user_id using the value of
// SSO_REQUIRED_GROUPS we set earlier.
if (r->user) {
return AUTHZ_GRANTED;
}
// Set the list of groups in the request notes, so that the
// sso authn handler can retrieve it and validate the ticket.
apr_table_setn(r->notes, "SSO_REQUIRED_GROUPS",
(char *)required_groups_charpp(r, parsed_require_args));
return AUTHZ_DENIED_NO_USER;
}
static const char *group_parse_config(cmd_parms *cmd, const char *require_line,
const void **parsed_require_line)
{
const char *expr_err = NULL;
ap_expr_info_t *expr;
expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT,
&expr_err, NULL);
if (expr_err) {
return apr_pstrcat(cmd->temp_pool,
"Cannot parse expression in require line: ",
expr_err, NULL);
}
*parsed_require_line = expr;
return NULL;
}
#else
static int mod_sso_auth_checker(request_rec *r)
{
const char *uri, *type;
......@@ -707,7 +960,7 @@ static int mod_sso_auth_checker(request_rec *r)
char *sso_logout_path, *sso_login_path;
modsso_config *s_cfg;
// We already did everything in mod_sso_authenticate_user(),
// We already did everything in mod_sso_check_user_id(),
// so just succeed (if SSO is active).
type = ap_auth_type(r);
if (type && !strcasecmp(type, "SSO") && r->user) {
......@@ -732,7 +985,15 @@ static int mod_sso_auth_checker(request_rec *r)
return DECLINED;
}
#endif
#if MODULE_MAGIC_NUMBER_MAJOR >= 20100714
static const authz_provider authz_sso_group_provider =
{
&group_check_authorization,
&group_parse_config,
};
#endif
/**
* Apache register_hooks callback for mod_sso.
......@@ -744,10 +1005,16 @@ static int mod_sso_auth_checker(request_rec *r)
*/
static void mod_sso_register_hooks (apr_pool_t *p)
{
static const char * const mssoPost[] = {"sso_module", NULL};
ap_hook_handler(mod_sso_method_handler, NULL, NULL, APR_HOOK_FIRST);
ap_hook_auth_checker(mod_sso_auth_checker, NULL, mssoPost, APR_HOOK_MIDDLE);
ap_hook_check_user_id(mod_sso_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
#if MODULE_MAGIC_NUMBER_MAJOR >= 20100714
ap_hook_check_authn(mod_sso_check_user_id, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_CONF);
ap_hook_check_access_ex(mod_sso_check_access_ex, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "group", "0", &authz_sso_group_provider, AP_AUTH_INTERNAL_PER_CONF);
#else
static const char * const authzSucc[] = { "mod_sso.c", NULL };
ap_hook_check_user_id(mod_sso_check_user_id, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_auth_checker(mod_sso_auth_checker, NULL, authzSucc, APR_HOOK_MIDDLE);
#endif
}
/*
......
......@@ -26,6 +26,10 @@
#include "ap_config.h"
#include "apr_strings.h"
#ifdef APLOG_USE_MODULE
APLOG_USE_MODULE(sso);
#endif
/* overwrite package vars set by apache */
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
......
public.key
*_unittest
*.log
*.trs
......@@ -6,7 +6,7 @@ check_PROGRAMS = \
EXTRA_DIST = httpd_integration_test.py
TESTS = $(check_PROGRAMS)
AM_CPPFLAGS += $(APACHE_CFLAGS) $(GTEST_CPPFLAGS)
AM_CPPFLAGS += $(APACHE_CFLAGS) $(APR_CFLAGS) $(GTEST_CPPFLAGS)
AM_LDFLAGS += $(GTEST_LDFLAGS)
LDADD = $(builddir)/../libmod_sso.la $(GTEST_LIBS) $(APR_LIBS) -laprutil-1
......
......@@ -17,6 +17,9 @@ for exe in (APACHE_BIN, APXS_BIN):
if not os.path.exists(exe):
raise Exception('%s not found, this test cannot run' % exe)
# Use 2.4 ocnfiguration.
APACHE_CONFIG = 'test-httpd-2.4.conf'
devnull = open(os.devnull)
......@@ -27,10 +30,12 @@ def _start_httpd(public_key):
env['TESTROOT'] = os.getcwd()
env['MODULEDIR'] = subprocess.check_output(
[APXS_BIN, '-q', 'LIBEXECDIR'], stderr=devnull).strip()
cmd = [APACHE_BIN, "-f", os.path.join(os.getcwd(), "test-httpd.conf"), "-X"]
cmd = [APACHE_BIN, "-f", os.path.join(os.getcwd(), APACHE_CONFIG), "-X"]
if os.getenv('STRACE'):
cmd = ['strace', '-s', '256', '-f'] + cmd
if os.getenv('VALGRIND'):
cmd = ['valgrind'] + cmd
httpd = subprocess.Popen(cmd, env=env)
print 'httpd pid:', httpd.pid
......@@ -136,12 +141,17 @@ class HttpdIntegrationTest(unittest.TestCase):
def mkcookie(tkt):
return "SSO_test=%s" % tkt
# Set to a non-empty string when testing the SSOGroups directive
# (normally only the requested groups are generated).
#extra_groups = "&g=group1,group2,group3"
extra_groups = ''
# Tests have a name so that we can recognize failures.
checks = [
("index -> redirect",
{"url": "/index.html",
"status": 302,
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Findex.html"}),
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Findex.html" + extra_groups}),
("index with cookie -> ok",
{"url": "/index.html",
"cookie": mkcookie(self._ticket()),
......@@ -151,12 +161,12 @@ class HttpdIntegrationTest(unittest.TestCase):
{"url": "/index.html",
"cookie": mkcookie('blahblah' * 8),
"status": 302,
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Findex.html"}),
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Findex.html" + extra_groups}),
("protected-user -> redirect",
{"url": "/protected-user/index.html",
"status": 302,
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Fprotected-user%2Findex.html"}),
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Fprotected-user%2Findex.html" + extra_groups}),
("protected-user with cookie -> ok",
{"url": "/protected-user/index.html",
"cookie": mkcookie(self._ticket()),
......@@ -170,28 +180,32 @@ class HttpdIntegrationTest(unittest.TestCase):
("protected-group -> redirect",
{"url": "/protected-group/index.html",
"status": 302,
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Fprotected-group%2Findex.html&g=group1"}),
"location": "https://login.example.com/?s=service.example.com%2F&d=https%3A%2F%2Fservice.example.com%2Fprotected-group%2Findex.html" + (extra_groups if extra_groups else "&g=group1")}),
("protected-group with cookie -> ok",
{"url": "/protected-group/index.html",
"cookie": mkcookie(self._ticket()),
"status": 200,
"body": "ok"}),
#("protected-group with cookie wrong group -> unauthorized",
# {"url": "/protected-group/index.html",
# "cookie": mkcookie(self._ticket(group="group2")),
# "status": 401}),
("protected-group with cookie wrong group -> redirect",