9a85282011-11-01Henrik Grubbström (Grubba) #pike __REAL_VERSION__
f5f8eb2011-10-31Henrik Grubbström (Grubba) inherit @module@ : ZXID;
bf8ec92011-10-27Henrik Grubbström (Grubba) 
9a85282011-11-01Henrik Grubbström (Grubba) final constant dont_dump_module = 1; #if constant(@module@.Configuration)
bf8ec92011-10-27Henrik Grubbström (Grubba) //! Convert a mapping of query variables to a query string. string(0..255) mapping_to_query(mapping(string(0..255):string(0..255)) map) { return predef::map((array(array(string)))map, lambda(array(string) pair) { return predef::map(pair, Protocols.HTTP.percent_encode) * "="; }) * "&"; }
5bc7082012-02-15Henrik Grubbström (Grubba) //!
bf8ec92011-10-27Henrik Grubbström (Grubba) class Configuration {
f657112011-11-24Henrik Grubbström (Grubba)  inherit ZXID::Configuration : Configuration;
bf8ec92011-10-27Henrik Grubbström (Grubba)  mapping(string(0..255):string(0..255)|array(string(0..255))) parse_conf_file(string file) { mapping(string(0..255):string(0..255)) conf = ([]);
ee484e2011-11-30Henrik Grubbström (Grubba)  if (!Stdio.exist(file)) return conf;
bf8ec92011-10-27Henrik Grubbström (Grubba)  Stdio.File f = Stdio.File(file, "r");
f5f8eb2011-10-31Henrik Grubbström (Grubba)  foreach(f->line_iterator(1);; string line) {
bf8ec92011-10-27Henrik Grubbström (Grubba)  foreach(line/"&", string frag) { sscanf(frag, "%*[ \t]%s=%s", string name, string val); if (!sizeof(name) || (name[0] == '#') || !val) continue; conf[Protocols.HTTP.uri_decode(name)] = Protocols.HTTP.uri_decode(val); } } return conf; }
2d6ae72012-02-13Henrik Grubbström (Grubba)  protected string url = "/";
bf8ec92011-10-27Henrik Grubbström (Grubba)  // Perform some parsing here. protected void create(mapping(string(0..255):string(0..255)|array(string(0..255))) conf) { conf += ([]); while(1) {
2d6ae72012-02-13Henrik Grubbström (Grubba)  url = conf->URL || url;
bf8ec92011-10-27Henrik Grubbström (Grubba)  if (stringp(conf->REDIRECT_HACK_ZXID_URL)) { array(string(0..255)) a = conf->REDIRECT_HACK_ZXID_URL/"?"; if (sizeof(a) > 1) { conf->REDIRECT_HACK_ZXID_QS = a[1..]*"?"; } conf->REDIRECT_HACK_ZXID_URL = a[0]; } if (stringp(conf->REQUIRED_AUTHNCTX)) { conf->REQUIRED_AUTHNCTX /= "$"; } ::create(conf); if (conf->PATH) { // Recurse. conf = parse_conf_file(combine_path(conf->PATH, "zxid.conf")); // FIXME: Loop detection. continue; } break; } }
5bc7082012-02-15Henrik Grubbström (Grubba)  //!
f657112011-11-24Henrik Grubbström (Grubba)  class Session
bf8ec92011-10-27Henrik Grubbström (Grubba)  {
f657112011-11-24Henrik Grubbström (Grubba)  inherit Configuration::Session;
3293c82011-11-28Henrik Grubbström (Grubba)  //! mapping(string:mixed) auth_info;
c56e4e2014-11-06Henrik Grubbström (Grubba)  //! mapping(string:mixed) get_auth_info() { return auth_info; }
3293c82011-11-28Henrik Grubbström (Grubba)  //! Authenticate via SAML given the query-string @[query]. //! //! @returns //! @mixed //! @type mapping(string(0..255):string(0..255)) //! Returns a mapping when interaction with the browser //! is needed. //! @type string
ee484e2011-11-30Henrik Grubbström (Grubba)  //! Returns a string to ask for some specific actions.
3293c82011-11-28Henrik Grubbström (Grubba)  //! @type zero //! Returns @expr{0@} (zero) on successfull authentication. //! @[auth_info] will be set with the corresponding user information. //! @endmixed //! //! @throws //! Throws errors on most error conditions.
a6a7c32014-11-04Henrik Grubbström (Grubba)  mixed authenticate(string(0..255) uri_path, string(0..255)|mapping(string(0..255):string(0..255)) query)
f657112011-11-24Henrik Grubbström (Grubba)  { if (mappingp(query)) query = mapping_to_query(query);
a6a7c32014-11-04Henrik Grubbström (Grubba)  string raw_res = ::authenticate(uri_path, query);
f657112011-11-24Henrik Grubbström (Grubba)  switch(sizeof(raw_res) && raw_res[0]) { case '*': // Error. error("SAML authentication failure: %s\n", raw_res[1..]); case '<': // HTML-content. return ([ "data":raw_res, "type":"text/html" ]); case 'L': // Location header.
2d6ae72012-02-13Henrik Grubbström (Grubba)  if (!has_prefix(raw_res, "Location:")) break;
f657112011-11-24Henrik Grubbström (Grubba)  raw_res =
8ff89d2016-07-04Martin Nilsson  String.trim((raw_res/"\r\n")[0][sizeof("Location:")..]);
2d6ae72012-02-13Henrik Grubbström (Grubba)  if (has_prefix(raw_res, "?")) { // Prefix with the URL. raw_res = url + raw_res; }
f657112011-11-24Henrik Grubbström (Grubba)  return ([ "error":Protocols.HTTP.HTTP_FOUND, "rettext":"Redirect to " + raw_res, "extra_heads":([ "Location":raw_res ]) ]); case 'n': // NOOP. break; case 'b': // Send SP metadata. // Should be handled by the C-layer already. break; case 'c': // Send SP CARML declaration. // Should be handled by the C-layer already. break; case 'e': // Send IdP selection page. break; case 'a': // Send authentication page (usually on the IdP). break; case 'd': // Authentication completed. LDIF-entry. break; case 'z': // Authentication failure.
2d6ae72012-02-13Henrik Grubbström (Grubba)  auth_info = UNDEFINED; return 0;
3293c82011-11-28Henrik Grubbström (Grubba)  case '{': // Success, JSON result. auth_info = Standards.JSON.decode(raw_res); return 0;
f657112011-11-24Henrik Grubbström (Grubba)  default:
3293c82011-11-28Henrik Grubbström (Grubba)  error("Unknown SAML response: %O\n", raw_res[..30]);
f657112011-11-24Henrik Grubbström (Grubba)  } return raw_res;
4b5cbe2011-11-14Henrik Grubbström (Grubba)  }
bf8ec92011-10-27Henrik Grubbström (Grubba)  }
f5f8eb2011-10-31Henrik Grubbström (Grubba) }
9a85282011-11-01Henrik Grubbström (Grubba) #endif