LCOV - code coverage report
Current view: top level - zxid - zxidsso.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 302 470 64.3 %
Date: 2010-12-19 Functions: 15 15 100.0 %
Branches: 202 430 47.0 %

           Branch data     Line data    Source code
       1                 :            : /* zxidsso.c  -  Handwritten functions for implementing Single Sign-On logic for SP
       2                 :            :  * Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
       4                 :            :  * Author: Sampo Kellomaki (sampo@iki.fi)
       5                 :            :  * This is confidential unpublished proprietary source code of the author.
       6                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       7                 :            :  * Distribution prohibited unless authorized in writing.
       8                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       9                 :            :  * $Id: zxidsso.c,v 1.64 2010-01-08 02:10:09 sampo Exp $
      10                 :            :  *
      11                 :            :  * 12.8.2006, created --Sampo
      12                 :            :  * 30.9.2006, added signature verification --Sampo
      13                 :            :  * 9.10.2007, added signing SOAP requests, Destination for redirects --Sampo
      14                 :            :  * 22.3.2008, permitted passing RelayState for SSO --Sampo
      15                 :            :  * 7.10.2008, added documentation --Sampo
      16                 :            :  * 1.2.2010,  added authentication service client --Sampo
      17                 :            :  *
      18                 :            :  * See also: http://hoohoo.ncsa.uiuc.edu/cgi/interface.html (CGI specification)
      19                 :            :  */
      20                 :            : 
      21                 :            : #include "platform.h"  /* needed on Win32 for snprintf() et al. */
      22                 :            : 
      23                 :            : #include <string.h>
      24                 :            : #include <stdio.h>
      25                 :            : #include <stdlib.h>
      26                 :            : #include <errno.h>
      27                 :            : #include <time.h>
      28                 :            : #include <sys/types.h>
      29                 :            : #include <sys/stat.h>
      30                 :            : 
      31                 :            : #include "errmac.h"
      32                 :            : #include "zx.h"
      33                 :            : #include "zxid.h"
      34                 :            : #include "zxidpriv.h"
      35                 :            : #include "zxidutil.h"
      36                 :            : #include "zxidconf.h"
      37                 :            : #include "saml2.h"
      38                 :            : #include "c/zx-const.h"
      39                 :            : #include "c/zx-ns.h"
      40                 :            : #include "c/zx-data.h"
      41                 :            : 
      42                 :            : /* ============== Generating and sending AuthnReq ============== */
      43                 :            : 
      44                 :            : /*() This function makes the policy decision about which profile to
      45                 :            :  * use. It is only used if there was no explicit specification in the
      46                 :            :  * CGI form (e.g. "Login (P)" button. Currently it's a stub that
      47                 :            :  * always picks the artifact profile. Eventually configuration options
      48                 :            :  * or cgi input can be used to determine the profile in a more
      49                 :            :  * sophisticated way. Often zxid_mk_authn_req() will override the
      50                 :            :  * return value of this function by its own inspection of the CGI
      51                 :            :  * variables. */
      52                 :            : 
      53                 :            : /* Called by:  zxid_start_sso_url */
      54                 :            : int zxid_pick_sso_profile(zxid_conf* cf, zxid_cgi* cgi, zxid_entity* idp_meta)
      55                 :          5 : {
      56                 :            :   /* More sophisticated policy may eventually go here. */
      57                 :          5 :   return ZXID_SAML2_ART;
      58                 :            : }
      59                 :            : 
      60                 :            : /*() Map name id format form field to SAML specified URN string. */
      61                 :            : /* Called by:  zxid_map_identity_token, zxid_mk_authn_req, zxid_nidmap_identity_token */
      62                 :            : const char* zxid_saml2_map_nid_fmt(const char* f)
      63                 :         17 : {
      64   [ +  +  +  +  :         17 :   switch (f[0]) {
          +  +  +  +  +  
                      + ]
      65                 :          1 :   case 'n' /*'none'*/:   return "";
      66                 :          8 :   case 'p' /*'prstnt'*/: return SAML2_PERSISTENT_NID_FMT;
      67                 :          1 :   case 't' /*'trnsnt'*/: return SAML2_TRANSIENT_NID_FMT;
      68                 :          1 :   case 'u' /*'unspfd'*/: return SAML2_UNSPECIFIED_NID_FMT;
      69                 :          1 :   case 'e' /*'emladr'*/: return SAML2_EMAILADDR_NID_FMT;
      70                 :          1 :   case 'x' /*'x509sn'*/: return SAML2_X509_NID_FMT;
      71                 :          1 :   case 'w' /*'windmn'*/: return SAML2_WINDOMAINQN_NID_FMT;
      72                 :          1 :   case 'k' /*'kerbrs'*/: return SAML2_KERBEROS_NID_FMT;
      73                 :          1 :   case 's' /*'saml'*/:   return SAML2_ENTITY_NID_FMT;
      74                 :          1 :   default:               return f;
      75                 :            :   }
      76                 :            : }
      77                 :            : 
      78                 :            : /*() Map protocol binding form field to SAML specified URN string. */
      79                 :            : /* Called by: */
      80                 :            : const char* zxid_saml2_map_protocol_binding(const char* b)
      81                 :          7 : {
      82   [ +  +  +  +  :          7 :   switch (b[0]) {
                +  +  + ]
      83                 :          1 :   case 'r' /*'redir'*/: return SAML2_REDIR;
      84                 :          1 :   case 'a' /*'art'*/:   return SAML2_ART;
      85                 :          1 :   case 'p' /*'post'*/:  return SAML2_POST;
      86                 :          1 :   case 'q' /*'qsimplesig'*/:  return SAML2_POST_SIMPLE_SIGN;
      87                 :          1 :   case 's' /*'soap'*/:  return SAML2_SOAP;
      88                 :            :   case 'e' /*'ecp'*/:
      89                 :          1 :     /*case 'paos':*/  return SAML2_PAOS;
      90                 :          1 :   default:      return b;
      91                 :            :   }
      92                 :            : }
      93                 :            : 
      94                 :            : /*() Map SAML protocol binding URN to form field. */
      95                 :            : /* Called by:  zxid_idp_sso x3, zxid_sp_loc_by_index_raw */
      96                 :            : int zxid_protocol_binding_map_saml2(struct zx_str* b)
      97                 :         13 : {
      98   [ +  +  +  -  :         13 :   if (!b || !b->len || !b->s) {
                   -  + ]
      99   [ -  +  #  # ]:          1 :     D("No binding supplied, assume redir %d", 0);
     100                 :          1 :     return 'r';
     101                 :            :   }
     102   [ +  +  +  + ]:         12 :   if (b->len == sizeof(SAML2_REDIR)-1 && !memcmp(b->s, SAML2_REDIR, b->len)) return 'r';
     103   [ +  +  +  - ]:         11 :   if (b->len == sizeof(SAML2_ART)-1   && !memcmp(b->s, SAML2_ART, b->len))   return 'a';
     104   [ +  +  +  - ]:         10 :   if (b->len == sizeof(SAML2_POST)-1  && !memcmp(b->s, SAML2_POST, b->len))  return 'p';
     105   [ +  +  +  - ]:          4 :   if (b->len == sizeof(SAML2_POST_SIMPLE_SIGN)-1  && !memcmp(b->s, SAML2_POST_SIMPLE_SIGN, b->len)) return 'q';
     106   [ +  +  +  + ]:          3 :   if (b->len == sizeof(SAML2_SOAP)-1  && !memcmp(b->s, SAML2_SOAP, b->len))  return 's';
     107   [ +  +  +  - ]:          2 :   if (b->len == sizeof(SAML2_PAOS)-1  && !memcmp(b->s, SAML2_PAOS, b->len))  return 'e';
     108   [ -  +  #  # ]:          1 :   D("Unknown binding(%.*s) supplied, assume redir.", b->len, b->s);
     109                 :          1 :   return 'r';
     110                 :            : }
     111                 :            : 
     112                 :            : /*() Map authentication contest class ref form field to SAML specified URN string. */
     113                 :            : /* Called by:  zxid_mk_authn_req */
     114                 :            : char* zxid_saml2_map_authn_ctx(char* c)
     115                 :          8 : {
     116   [ +  +  +  +  :          8 :   switch (c[0]) {
                   +  + ]
     117                 :          1 :   case 'n' /*'none'*/:      return "";
     118                 :            :   case 'p':
     119   [ +  +  +  - ]:          3 :     switch (c[2]) {
     120                 :          1 :     case 'p' /*'pwp'*/:     return SAML_AUTHCTX_PASSWORDPROTECTED;
     121                 :          1 :     case 0   /*'pw'*/:      return SAML_AUTHCTX_PASSWORD;
     122                 :          1 :     case 'v' /*'prvses'*/:  return SAML_AUTHCTX_PREVSESS;
     123                 :            :     }
     124                 :          0 :     break;
     125                 :          1 :   case 'c' /*'clicert'*/:   return SAML_AUTHCTX_SSL_TLS_CERT;
     126                 :          1 :   case 'u' /*'unspcf'*/:    return SAML_AUTHCTX_UNSPCFD;
     127                 :          1 :   case 'i' /*'ip'*/:        return SAML_AUTHCTX_INPROT;
     128                 :            :   }
     129                 :          1 :   return c;
     130                 :            : }
     131                 :            : 
     132                 :            : /*(i) Generate an authentication request and make a URL out of it.
     133                 :            :  * cf::     Used for many configuration options and memory allocation
     134                 :            :  * cgi::    Used to pick the desired SSO profile based on hidden fields or user input.
     135                 :            :  * return:: Redirect URL as zx_str. Caller should eventually free this memory.
     136                 :            :  */
     137                 :            : /* Called by:  zxid_start_sso, zxid_start_sso_location */
     138                 :            : struct zx_str* zxid_start_sso_url(zxid_conf* cf, zxid_cgi* cgi)
     139                 :          6 : {
     140                 :            :   struct zx_md_SingleSignOnService_s* sso_svc;
     141                 :            :   struct zx_sp_AuthnRequest_s* ar;
     142                 :            :   struct zx_str* ars;
     143                 :            :   int sso_profile_ix;
     144                 :            :   zxid_entity* idp_meta;
     145                 :          6 :   D_INDENT("start_sso: ");
     146   [ +  -  +  +  :          6 :   D("start_sso: cgi=%p cgi->eid=%p eid(%s)", cgi, cgi->eid, cgi->eid?cgi->eid:"-");
                   -  + ]
     147   [ +  +  +  -  :          6 :   if (!cgi->pr_ix || !cgi->eid || !cgi->eid[0]) {
                   -  + ]
     148   [ +  -  -  + ]:          1 :     D("Either protocol index or entity ID missing %d", cgi->pr_ix);
     149                 :          1 :     cgi->err = "IdP URL Missing or incorrect";
     150                 :          1 :     D_DEDENT("start_sso: ");
     151                 :          1 :     return 0;
     152                 :            :   }
     153                 :          5 :   idp_meta = zxid_get_ent(cf, cgi->eid);
     154         [ -  + ]:          5 :   if (!idp_meta) {
     155                 :          0 :     cgi->err = "IdP URL incorrect or IdP does not support fetching metadata from that URL.";
     156                 :          0 :     D_DEDENT("start_sso: ");
     157                 :          0 :     return 0;
     158                 :            :   }
     159         [ +  - ]:          5 :   switch (sso_profile_ix = zxid_pick_sso_profile(cf, cgi, idp_meta)) {
     160                 :            :   case ZXID_SAML2_ART:
     161                 :            :   case ZXID_SAML2_POST:
     162                 :            :   case ZXID_SAML2_POST_SIMPLE_SIGN:
     163         [ -  + ]:          5 :     if (!idp_meta->ed->IDPSSODescriptor) {
     164                 :          0 :       ERR("Entity(%s) does not have IdP SSO Descriptor (metadata problem)", cgi->eid);
     165                 :          0 :       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "ERR", cgi->eid, "No IDPSSODescriptor");
     166                 :          0 :       cgi->err = "Bad IdP metadata. Try different IdP.";
     167                 :          0 :       D_DEDENT("start_sso: ");
     168                 :          0 :       return 0;
     169                 :            :     }
     170                 :          5 :     for (sso_svc = idp_meta->ed->IDPSSODescriptor->SingleSignOnService;
     171   [ +  -  +  - ]:         10 :          sso_svc && sso_svc->gg.g.tok == zx_md_SingleSignOnService_ELEM;
     172                 :          0 :          sso_svc = (struct zx_md_SingleSignOnService_s*)sso_svc->gg.g.n)
     173   [ +  -  +  - ]:          5 :       if (sso_svc->Binding && !memcmp(SAML2_REDIR, sso_svc->Binding->g.s, sso_svc->Binding->g.len))
     174                 :          5 :         break;
     175         [ -  + ]:          5 :     if (!sso_svc) {
     176                 :          0 :       ERR("IdP Entity(%s) does not have any IdP SSO Service with " SAML2_REDIR " binding (metadata problem)", cgi->eid);
     177                 :          0 :       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "ERR", cgi->eid, "No redir binding");
     178                 :          0 :       cgi->err = "Bad IdP metadata. Try different IdP.";
     179                 :          0 :       D_DEDENT("start_sso: ");
     180                 :          0 :       return 0;
     181                 :            :     }
     182                 :          5 :     ar = zxid_mk_authn_req(cf, cgi);
     183                 :          5 :     ar->Destination = sso_svc->Location;
     184                 :          5 :     ars = zx_easy_enc_elem_opt(cf, &ar->gg);
     185   [ +  -  -  + ]:          5 :     D("AuthnReq(%.*s)", ars->len, ars->s);
     186                 :            :     break;
     187                 :            :   default:
     188   [ #  #  #  # ]:          0 :     NEVER("Inappropriate SSO profile: %d", sso_profile_ix);
     189                 :          0 :     cgi->err = "Inappropriate SSO profile. Bad metadata?";
     190                 :          0 :     D_DEDENT("start_sso: ");
     191                 :          0 :     return 0;
     192                 :            :   }
     193         [ +  - ]:          5 :   if (cf->log_level>0)
     194                 :          5 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "ANREDIR", cgi->eid, 0);
     195                 :          5 :   ars = zxid_saml2_redir_url(cf, &sso_svc->Location->g, ars, cgi->rs);
     196                 :          5 :   D_DEDENT("start_sso: ");
     197                 :          5 :   return ars;
     198                 :            : }
     199                 :            : 
     200                 :            : /*() Wrapper for zxid_start_sso_url(), used in CGI scripts. */
     201                 :            : 
     202                 :            : /* Called by:  main x2, zxid_simple_no_ses_cf */
     203                 :            : int zxid_start_sso(zxid_conf* cf, zxid_cgi* cgi)
     204                 :          3 : {
     205                 :          3 :   struct zx_str* url = zxid_start_sso_url(cf, cgi);
     206         [ +  + ]:          3 :   if (!url)
     207                 :          1 :     return 0;
     208                 :          2 :   printf("Location: %.*s" CRLF2, url->len, url->s);
     209                 :          2 :   return ZXID_REDIR_OK;
     210                 :            : }
     211                 :            : 
     212                 :            : /*() Wrapper for zxid_start_sso_url(), used when Location header needs to be passed outside.
     213                 :            :  * return:: Location header as zx_str. Caller should eventually free this memory. */
     214                 :            : 
     215                 :            : /* Called by:  zxid_simple_no_ses_cf */
     216                 :            : struct zx_str* zxid_start_sso_location(zxid_conf* cf, zxid_cgi* cgi)
     217                 :          3 : {
     218                 :            :   struct zx_str* ss;
     219                 :          3 :   struct zx_str* url = zxid_start_sso_url(cf, cgi);
     220         [ -  + ]:          3 :   if (!url)
     221                 :          0 :     return 0; //zx_dup_str(cf->ctx, "* ERR");
     222                 :          3 :   ss = zx_strf(cf->ctx, "Location: %.*s" CRLF2, url->len, url->s);
     223                 :          3 :   zx_str_free(cf->ctx, url);
     224                 :          3 :   return ss;
     225                 :            : }
     226                 :            : 
     227                 :            : /* ============== Process Response and SSO Assertion ============== */
     228                 :            : 
     229                 :            : /*(i) Dereference an artifact to obtain an assertion. This is the last
     230                 :            :  * step in artifact SSO profile and involved making a SOAP call to the
     231                 :            :  * IdP. The artifact is received in saml_art CGI field, <<see:
     232                 :            :  * zxid_parse_cgi()>> where SAMLart query string argument is parsed. */
     233                 :            : 
     234                 :            : /* Called by:  main x2, zxid_simple_no_ses_cf */
     235                 :            : int zxid_sp_deref_art(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses)
     236                 :          1 : {
     237                 :            :   struct zx_md_ArtifactResolutionService_s* ar_svc;
     238                 :            :   struct zx_e_Body_s* body;
     239                 :            :   struct zx_root_s* r;
     240                 :            :   zxid_entity* idp_meta;
     241                 :            :   int len;
     242                 :            :   char end_pt_ix[16];
     243                 :            :   char* raw_succinct_id;
     244                 :            :   /*char* msg_handle;*/
     245                 :            :   char* p;
     246                 :            :   char buf[64];
     247                 :          1 :   D_INDENT("deref: ");
     248                 :            : 
     249   [ +  -  -  +  :          1 :   if (!cgi || !cgi->saml_art || !*cgi->saml_art) {
                   #  # ]
     250         [ +  - ]:          1 :     ERR("SAMLart missing or empty string. %p %p", cgi, cgi?cgi->saml_art:0);
     251         [ +  - ]:          1 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ERR", cgi?cgi->saml_art:0, "Artifact missing");
     252                 :          1 :     D_DEDENT("deref: ");
     253                 :          1 :     return 0;
     254                 :            :   }
     255                 :            :   
     256                 :          0 :   len = strlen(cgi->saml_art);
     257         [ #  # ]:          0 :   if (cf->log_level > 0)
     258   [ #  #  #  #  :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "W", "ART", cgi->saml_art, 0);
                   #  # ]
     259         [ #  # ]:          0 :   if (len-7 >= sizeof(buf)*4/3) {
     260                 :          0 :     ERR("SAMLart(%s), %d chars, too long. Max(%d) chars.", cgi->saml_art, len, sizeof(buf)*4/3+6);
     261                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ERR", cgi->saml_art, "Artifact too long");
     262                 :          0 :     D_DEDENT("deref: ");
     263                 :          0 :     return 0;
     264                 :            :   }
     265                 :          0 :   p = unbase64_raw(cgi->saml_art, cgi->saml_art + len, buf, zx_std_index_64);
     266                 :          0 :   *p = 0;
     267         [ #  # ]:          0 :   if (buf[0])
     268                 :          0 :     goto badart;
     269      [ #  #  # ]:          0 :   switch (buf[1]) {
     270                 :            :   case 0x03: /* SAML 1.1 */
     271                 :          0 :     end_pt_ix[0] = 0;
     272                 :          0 :     raw_succinct_id = buf + 2;
     273                 :            :     /*msg_handle = buf + 22;*/
     274                 :          0 :     break;
     275                 :            :   case 0x04: /* SAML 2.0 */
     276                 :          0 :     sprintf(end_pt_ix, "%d", (unsigned)buf[2] << 8 | (unsigned)buf[3]);
     277                 :          0 :     raw_succinct_id = buf + 4;
     278                 :            :     /*msg_handle = buf + 24;*/
     279                 :          0 :     break;
     280                 :          0 :   default: goto badart;
     281                 :            :   }
     282                 :            :   
     283                 :          0 :   idp_meta = zxid_get_ent_by_succinct_id(cf, raw_succinct_id);
     284   [ #  #  #  # ]:          0 :   if (!idp_meta || !idp_meta->eid) {
     285                 :          0 :     ERR("Unable to dereference SAMLart(%s). Can not find metadata for IdP. %p", cgi->saml_art, idp_meta);
     286                 :          0 :     D_DEDENT("deref: ");
     287                 :          0 :     return 0;
     288                 :            :   }
     289                 :            :   
     290      [ #  #  # ]:          0 :   switch (buf[1]) {
     291                 :            :   case 0x03: /* SAML 1.1 */
     292                 :            :     /* *** ff12_resolve_art() */
     293                 :          0 :     break;
     294                 :            :   case 0x04: /* SAML 2.0 */
     295         [ #  # ]:          0 :     if (!idp_meta->ed->IDPSSODescriptor) {
     296                 :          0 :       ERR("Entity(%s) does not have IdP SSO Descriptor (metadata problem)", idp_meta->eid);
     297                 :          0 :       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "ERR", 0, "No IDPSSODescriptor eid(%s)", idp_meta->eid);
     298                 :          0 :       D_DEDENT("deref: ");
     299                 :          0 :       return 0;
     300                 :            :     }
     301                 :          0 :     for (ar_svc = idp_meta->ed->IDPSSODescriptor->ArtifactResolutionService;
     302   [ #  #  #  # ]:          0 :          ar_svc && ar_svc->gg.g.tok == zx_md_ArtifactResolutionService_ELEM;
     303                 :          0 :          ar_svc = (struct zx_md_ArtifactResolutionService_s*)ar_svc->gg.g.n)
     304   [ #  #  #  #  :          0 :       if (ar_svc->Binding  && !memcmp(SAML2_SOAP, ar_svc->Binding->g.s, ar_svc->Binding->g.len)
          #  #  #  #  #  
                      # ]
     305                 :            :           && ar_svc->index && !memcmp(end_pt_ix, ar_svc->index->g.s, ar_svc->index->g.len)
     306                 :            :           && ar_svc->Location)
     307                 :          0 :         break;
     308         [ #  # ]:          0 :     if (!ar_svc) {
     309                 :          0 :       ERR("Entity(%s) does not have any IdP Artifact Resolution Service with " SAML2_SOAP " binding and index(%s) (metadata problem)", idp_meta->eid, end_pt_ix);
     310                 :          0 :       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "ERR", 0, "No Artifact Resolution Svc eid(%s) ep_ix(%s)", idp_meta->eid, end_pt_ix);
     311                 :          0 :       D_DEDENT("deref: ");
     312                 :          0 :       return 0;
     313                 :            :     }
     314                 :            :     
     315                 :          0 :     body = zx_NEW_e_Body(cf->ctx,0);
     316                 :          0 :     body->ArtifactResolve = zxid_mk_art_deref(cf, idp_meta, cgi->saml_art);
     317                 :          0 :     r = zxid_soap_call_hdr_body(cf, &ar_svc->Location->g, 0, body);
     318                 :          0 :     len =  zxid_sp_soap_dispatch(cf, cgi, ses, r);
     319                 :          0 :     D_DEDENT("deref: ");
     320                 :          0 :     return len;
     321                 :            :   default: goto badart;
     322                 :            :   }
     323                 :            :   
     324                 :          0 :  badart:
     325                 :          0 :   ERR("Bad SAMLart type code 0x%02x 0x%02x", buf[0], buf[1]);
     326                 :          0 :   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ERR", 0, "Bad SAMLart type code 0x%02x 0x%02x", buf[0], buf[1]);
     327                 :          0 :   D_DEDENT("deref: ");
     328                 :          0 :   return 0;
     329                 :            : }
     330                 :            : 
     331                 :            : /*() Map ZXSIG constant to letter for log and string message. */
     332                 :            : 
     333                 :            : /* Called by:  zxid_chk_sig, zxid_decode_redir_or_post, zxid_sp_sso_finalize, zxid_wsc_valid_re_env, zxid_wsf_validate_a7n, zxid_wsp_validate_env */
     334                 :            : void zxid_sigres_map(int sigres, char** sigval, char** sigmsg)
     335                 :        222 : {
     336   [ +  +  +  +  :        222 :   switch (sigres) {
          +  +  +  +  +  
                   +  + ]
     337                 :            :   case ZXSIG_OK:
     338   [ +  +  -  + ]:        211 :     D("Signature validated. %d", 1);
     339                 :        211 :     *sigval = "O";
     340                 :        211 :     *sigmsg = "Signature validated.";
     341                 :        211 :     break;
     342                 :            :   case ZXSIG_BAD_DALGO:  /* 1 Unsupported digest algorithm. */
     343                 :          1 :     ERR("Bad digest algo. %d", sigres);
     344                 :          1 :     *sigval = "A";
     345                 :          1 :     *sigmsg = "Unsupported digest algorithm. Signature can not be validated.";
     346                 :          1 :     break;
     347                 :            :   case ZXSIG_DIGEST_LEN: /* 2 Wrong digest length. */
     348                 :          1 :     ERR("Bad digest length. %d", sigres);
     349                 :          1 :     *sigval = "G";
     350                 :          1 :     *sigmsg = "Wrong digest length. Signature can not be validated.";
     351                 :          1 :     break;
     352                 :            :   case ZXSIG_BAD_DIGEST: /* 3 Digest value does not match. */
     353                 :          2 :     ERR("Bad digest. Canon problem? %d", sigres);
     354                 :          2 :     *sigval = "G";
     355                 :          2 :     *sigmsg = "Message digest does not match signed content. Canonicalization problem? Or falsified or altered or substituted content. Signature can not be validated.";
     356                 :          2 :     break;
     357                 :            :   case ZXSIG_BAD_SALGO:  /* 4 Unsupported signature algorithm. */
     358                 :          1 :     ERR("Bad sig algo. %d", sigres);
     359                 :          1 :     *sigval = "A";
     360                 :          1 :     *sigmsg = "Unsupported signature algorithm. Signature can not be validated.";
     361                 :          1 :     break;
     362                 :            :   case ZXSIG_BAD_CERT:   /* 5 Extraction of public key from certificate failed. */
     363                 :          1 :     ERR("Bad cert. %d", sigres);
     364                 :          1 :     *sigval = "I";
     365                 :          1 :     *sigmsg = "Bad IdP certificate or bad IdP metadata or unknown IdP. Signature can not be validated.";
     366                 :          1 :     break;
     367                 :            :   case ZXSIG_VFY_FAIL:   /* 6 Verification of signature failed. */
     368                 :          1 :     ERR("Bad sig. %d", sigres);
     369                 :          1 :     *sigval = "R";
     370                 :          1 :     *sigmsg = "Signature does not match signed content (but content checksum matches). Content may have been falsified, altered, or substituted; or IdP metadata does not match the keys actually used by the IdP.";
     371                 :          1 :     break;
     372                 :            :   case ZXSIG_NO_SIG:
     373                 :          1 :     ERR("Not signed. %d", sigres);
     374                 :          1 :     *sigval = "N";
     375                 :          1 :     *sigmsg = "No signature found.";
     376                 :          1 :     break;
     377                 :            :   case ZXSIG_TIMEOUT:
     378                 :          1 :     ERR("Out of validity period. %d", sigres);
     379                 :          1 :     *sigval = "V";
     380                 :          1 :     *sigmsg = "Assertion is not in its validity period.";
     381                 :          1 :     break;
     382                 :            :   case ZXSIG_AUDIENCE:
     383                 :          1 :     ERR("Wrong audience. %d", sigres);
     384                 :          1 :     *sigval = "V";
     385                 :          1 :     *sigmsg = "Assertion has wrong audience.";
     386                 :          1 :     break;
     387                 :            :   default:
     388                 :          1 :     ERR("Other sig err(%d)", sigres);
     389                 :          1 :     *sigval = "E";
     390                 :          1 :     *sigmsg = "Broken or unvalidatable signature.";
     391                 :            :   }
     392                 :        222 : }
     393                 :            : 
     394                 :            : /*(i) Validates conditions required by Liberty Alliance SAML2 conformance testing.
     395                 :            :  *
     396                 :            :  * May eventually validate additional conditions as well (this is the right place
     397                 :            :  * to add them). N.B. It is not an error if a condition is missing, or there
     398                 :            :  * is no Conditions element at all.
     399                 :            :  *
     400                 :            :  * cf::      Configuration object, used to determine time slops. Potentially
     401                 :            :  *     used for memory allocation via cf->ctx.
     402                 :            :  * cgi::     Optional CGI object. If non-NULL, sigval and sigmsg will be set.
     403                 :            :  * ses::     Optional session object. If non-NULL, then sigres code will be set.
     404                 :            :  * a7n::     Assertion whose conditions are checked.
     405                 :            :  * myentid:: Entity ID used for checking audience restriction. Typically from zxid_my_ent_id(cf)
     406                 :            :  * ourts::   Timestamp for validating NotOnOrAfter and NotBefore.
     407                 :            :  * err::     Result argument: Error letter (as may appear in audit log entry). The returned
     408                 :            :  *     string will be a constant and MUST NOT be freed by the caller.
     409                 :            :  * return::  0 (ZXSIG_OK) if validation was successful, otherwise a ZXSIG error code. */
     410                 :            : 
     411                 :            : /* Called by:  zxid_sp_sso_finalize, zxid_wsf_validate_a7n */
     412                 :            : int zxid_validate_cond(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, zxid_a7n* a7n, struct zx_str* myentid, struct timeval* ourts, char** err)
     413                 :         45 : {
     414                 :            :   struct timeval tsbuf;
     415                 :            :   struct zx_sa_AudienceRestriction_s* audr;
     416                 :            :   struct zx_elem_s* aud;
     417                 :            :   struct zx_str* ss;
     418                 :            :   int secs;
     419                 :            : 
     420   [ +  -  -  + ]:         45 :   if (!a7n || !a7n->Conditions) {
     421                 :          0 :     INFO("Assertion does not have Conditions. %p", a7n);
     422                 :          0 :     return ZXSIG_OK;
     423                 :            :   }
     424   [ +  -  -  + ]:         45 :   if (!myentid || !myentid->len) {
     425                 :          0 :     ERR("My entity ID missing %p", myentid);
     426                 :          0 :     return ZXSIG_OK;
     427                 :            :   }
     428                 :            : 
     429         [ +  + ]:         45 :   if (!ourts) {
     430                 :         35 :     GETTIMEOFDAY(&tsbuf, 0);
     431                 :         35 :     ourts = &tsbuf;
     432                 :            :   }
     433                 :            : 
     434         [ +  - ]:         45 :   if (a7n->Conditions->AudienceRestriction) {
     435                 :         45 :     for (audr = a7n->Conditions->AudienceRestriction;
     436   [ +  -  +  - ]:         90 :          audr && audr->gg.g.tok == zx_sa_AudienceRestriction_ELEM;
     437                 :          0 :          audr = (struct zx_sa_AudienceRestriction_s*)audr->gg.g.n) {
     438                 :         45 :       for (aud = audr->Audience;
     439   [ +  -  +  - ]:         90 :            aud && aud->g.tok == zx_sa_Audience_ELEM;
     440                 :          0 :            aud = (struct zx_elem_s*)aud->g.n) {
     441   [ +  -  +  -  :         45 :         ss = ZX_GET_CONTENT(aud);
                   +  - ]
     442   [ +  -  #  #  :         45 :         if (ss?ss->len:0 == myentid->len && !memcmp(ss->s, myentid->s, ss->len)) {
             #  #  +  - ]
     443   [ +  +  -  + ]:         45 :           D("Found audience. %d", 0);
     444                 :         45 :           goto found_audience;
     445                 :            :         }
     446                 :            :       }
     447                 :            :     }
     448         [ #  # ]:          0 :     if (cgi) {
     449                 :          0 :       cgi->sigval = "V";
     450                 :          0 :       cgi->sigmsg = "This SP not included in the Assertion Audience.";
     451                 :            :     }
     452         [ #  # ]:          0 :     if (ses)
     453                 :          0 :       ses->sigres = ZXSIG_AUDIENCE;
     454         [ #  # ]:          0 :     if (cf->audience_fatal) {
     455                 :          0 :       ERR("SSO error: AudienceRestriction wrong. My entityID(%.*s)", myentid->len, myentid->s);
     456         [ #  # ]:          0 :       if (err)
     457                 :          0 :         *err = "P";
     458                 :          0 :       return ZXSIG_AUDIENCE;
     459                 :            :     } else {
     460                 :          0 :       INFO("SSO warn: AudienceRestriction wrong. My entityID(%.*s). Configured to ignore this (AUDIENCE_FATAL=0).", myentid->len, myentid->s);
     461                 :            :     }
     462                 :            :   } else {
     463                 :          0 :     INFO("Assertion does not have AudienceRestriction. %d", 0);
     464                 :            :   }
     465                 :         45 :  found_audience:
     466                 :            :   
     467   [ +  -  +  - ]:         90 :   if (a7n->Conditions->NotOnOrAfter && a7n->Conditions->NotOnOrAfter->g.len > 18) {
     468                 :         45 :     secs = zx_date_time_to_secs(a7n->Conditions->NotOnOrAfter->g.s);
     469         [ +  + ]:         45 :     if (secs <= ourts->tv_sec) {
     470         [ +  - ]:          6 :       if (secs + cf->after_slop <= ourts->tv_sec) {
     471                 :          6 :         ERR("NotOnOrAfter rejected with slop of %d. Time to expiry %ld secs. Our gettimeofday: %ld secs, remote: %d secs", cf->after_slop, secs - ourts->tv_sec, ourts->tv_sec, secs);
     472         [ +  - ]:          6 :         if (cgi) {
     473                 :          6 :           cgi->sigval = "V";
     474                 :          6 :           cgi->sigmsg = "Assertion has expired.";
     475                 :            :         }
     476         [ +  - ]:          6 :         if (ses)
     477                 :          6 :           ses->sigres = ZXSIG_TIMEOUT;
     478         [ -  + ]:          6 :         if (cf->timeout_fatal) {
     479         [ #  # ]:          0 :           if (err)
     480                 :          0 :             *err = "P";
     481                 :          0 :           return ZXSIG_TIMEOUT;
     482                 :            :         }
     483                 :            :       } else {
     484   [ #  #  #  # ]:          0 :         D("NotOnOrAfter accepted with slop of %d. Time to expiry %ld secs. Our gettimeofday: %ld secs, remote: %d secs", cf->after_slop, secs - ourts->tv_sec, ourts->tv_sec, secs);
     485                 :            :       }
     486                 :            :     } else {
     487   [ +  -  -  + ]:         39 :       D("NotOnOrAfter ok. Time to expiry %ld secs. Our gettimeofday: %ld secs, remote: %d secs", secs - ourts->tv_sec, ourts->tv_sec, secs);
     488                 :            :     }
     489                 :            :   } else {
     490                 :          0 :     INFO("Assertion does not have NotOnOrAfter. %d", 0);
     491                 :            :   }
     492                 :            :   
     493   [ +  -  +  - ]:         90 :   if (a7n->Conditions->NotBefore && a7n->Conditions->NotBefore->g.len > 18) {
     494                 :         45 :     secs = zx_date_time_to_secs(a7n->Conditions->NotBefore->g.s);
     495         [ -  + ]:         45 :     if (secs > ourts->tv_sec) {
     496         [ #  # ]:          0 :       if (secs - cf->before_slop > ourts->tv_sec) {
     497                 :          0 :         ERR("NotBefore rejected with slop of %d. Time to validity %ld secs. Our gettimeofday: %ld secs, remote: %d secs", cf->before_slop, secs - ourts->tv_sec, ourts->tv_sec, secs);
     498         [ #  # ]:          0 :         if (cgi) {
     499                 :          0 :           cgi->sigval = "V";
     500                 :          0 :           cgi->sigmsg = "Assertion is not valid yet (too soon).";
     501                 :            :         }
     502         [ #  # ]:          0 :         if (ses)
     503                 :          0 :           ses->sigres = ZXSIG_TIMEOUT;
     504         [ #  # ]:          0 :         if (cf->timeout_fatal) {
     505         [ #  # ]:          0 :           if (err)
     506                 :          0 :             *err = "P";
     507                 :          0 :           return ZXSIG_TIMEOUT;
     508                 :            :         }
     509                 :            :       } else {
     510   [ #  #  #  # ]:          0 :         D("NotBefore accepted with slop of %d. Time to validity %ld secs. Our gettimeofday: %ld secs, remote: %d secs", cf->before_slop, secs - ourts->tv_sec, ourts->tv_sec, secs);
     511                 :            :       }
     512                 :            :     } else {
     513   [ +  +  -  + ]:         45 :       D("NotBefore ok. Time from validity %ld secs. Our gettimeofday: %ld secs, remote: %d secs", ourts->tv_sec - secs, ourts->tv_sec, secs);
     514                 :            :     }
     515                 :            :   } else {
     516                 :          0 :     INFO("Assertion does not have NotBefore. %d", 0);
     517                 :            :   }
     518                 :         45 :   return ZXSIG_OK;
     519                 :            : }
     520                 :            : 
     521                 :            : struct zx_str unknown_str = {0,0,1,"??"};  /* Static string used as dummy value. */
     522                 :            : 
     523                 :            : /*(i) zxid_sp_sso_finalize() gets called irrespective of binding (POST, Artifact)
     524                 :            :  * and validates the SSO a7n, including the authentication statement.
     525                 :            :  * Then, it creates session and optionally user entry.
     526                 :            :  *
     527                 :            :  * cf::  Configuration object, used to determine time slops, potentially memalloc via cf->ctx
     528                 :            :  * cgi:: CGI object. sigval and sigmsg may be set.
     529                 :            :  * ses:: Session object. Will be modified according to new session created from the SSO assertion.
     530                 :            :  * a7n:: Single Sign-On assertion
     531                 :            :  * return:: 0 for failure, otherwise some success code such as ZXID_SSO_OK */
     532                 :            : 
     533                 :            : /* Called by:  main, sig_validate, zxid_sp_dig_sso_a7n */
     534                 :            : int zxid_sp_sso_finalize(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, zxid_a7n* a7n, struct zx_ns_s* pop_seen)
     535                 :         10 : {
     536                 :         10 :   char* err = "S"; /* See: RES in zxid-log.pd, section "ZXID Log Format" */
     537                 :            :   struct timeval ourts;
     538                 :         10 :   struct timeval srcts = {0,501000};
     539                 :            :   struct zx_str* logpath;
     540                 :         10 :   struct zx_str* issuer = &unknown_str;
     541                 :         10 :   struct zx_str* subj = &unknown_str;
     542                 :            :   struct zx_str* ss;
     543                 :            :   struct zxsig_ref refs;
     544                 :            :   zxid_entity* idp_meta;
     545                 :            :   /*ses->sigres = ZXSIG_NO_SIG; set earlier, do not overwrite */
     546                 :         10 :   ses->a7n = a7n;
     547                 :         10 :   ses->rs = cgi->rs;
     548                 :         10 :   ses->ssores = 1;
     549                 :         10 :   GETTIMEOFDAY(&ourts, 0);
     550                 :            :   
     551                 :         10 :   D_INDENT("ssof: ");
     552                 :            : 
     553   [ +  -  -  + ]:         10 :   if (!a7n || !a7n->AuthnStatement) {
     554                 :          0 :     ERR("SSO failed: no assertion supplied, or assertion didn't contain AuthnStatement. %p", a7n);
     555                 :          0 :     goto erro;
     556                 :            :   }
     557   [ +  -  +  -  :         10 :   if (!a7n->IssueInstant || !a7n->IssueInstant->g.len || !a7n->IssueInstant->g.s || !a7n->IssueInstant->g.s[0]) {
             +  -  -  + ]
     558                 :          0 :     ERR("SSO failed: assertion does not have IssueInstant or it is empty. %p", a7n->IssueInstant);
     559                 :          0 :     goto erro;
     560                 :            :   }
     561                 :         10 :   srcts.tv_sec = zx_date_time_to_secs(a7n->IssueInstant->g.s);
     562   [ +  -  +  -  :         10 :   if (!(issuer = ZX_GET_CONTENT(a7n->Issuer))) {
             +  -  -  + ]
     563                 :          0 :     ERR("SSO failed: assertion does not have Issuer. %p", a7n->Issuer);
     564                 :          0 :     goto erro;
     565                 :            :   }
     566                 :            :   
     567                 :            :   /* See zxid_wsp_validate() for similar code. *** consider factoring out commonality */
     568                 :            :   
     569         [ -  + ]:         10 :   if (!a7n->Subject) {
     570                 :          0 :     ERR("SSO failed: assertion does not have Subject. %p", a7n);
     571                 :          0 :     goto erro;
     572                 :            :   }
     573                 :            : 
     574                 :         10 :   ses->nameid = zxid_decrypt_nameid(cf, a7n->Subject->NameID, a7n->Subject->EncryptedID);
     575   [ +  -  +  -  :         10 :   if (!(subj = ZX_GET_CONTENT(ses->nameid))) {
             +  -  -  + ]
     576                 :          0 :     ERR("SSO failed: assertion does not have Subject->NameID. %p", ses->nameid);
     577                 :          0 :     goto erro;
     578                 :            :   }
     579                 :            :   
     580                 :         10 :   ses->nid = zx_str_to_c(cf->ctx, subj);
     581   [ +  -  -  + ]:         10 :   if (ses->nameid->Format && !memcmp(ses->nameid->Format->g.s, SAML2_TRANSIENT_NID_FMT, ses->nameid->Format->g.len)) {
     582                 :          0 :     ses->nidfmt = 0;
     583                 :            :   } else {
     584                 :         10 :     ses->nidfmt = 1;  /* anything nontransient may be a federation */
     585                 :            :   }
     586                 :            : 
     587                 :            :   /* In SSO the acting identity and the target identity are the same */
     588                 :         10 :   ses->tgta7n = ses->a7n;
     589                 :         10 :   ses->tgtnameid = ses->nameid;
     590                 :         10 :   ses->tgt = ses->nid;
     591                 :         10 :   ses->tgtfmt = ses->nidfmt;
     592                 :            : 
     593         [ +  - ]:         10 :   if (a7n->AuthnStatement->SessionIndex)
     594                 :         10 :     ses->sesix = zx_str_to_c(cf->ctx, &a7n->AuthnStatement->SessionIndex->g);
     595                 :            :   
     596   [ +  +  +  -  :         10 :   D("SSOA7N received. NID(%s) FMT(%d) SESIX(%s)", ses->nid, ses->nidfmt, ses->sesix?ses->sesix:"");
                   -  + ]
     597                 :            :   
     598                 :            :   /* Validate signature (*** add Issuer trusted check, CA validation, etc.) */
     599                 :            :   
     600                 :         10 :   idp_meta = zxid_get_ent_ss(cf, issuer);
     601         [ -  + ]:         10 :   if (!idp_meta) {
     602                 :          0 :     ERR("Unable to find metadata for Issuer(%.*s).", issuer->len, issuer->s);
     603                 :          0 :     cgi->sigval = "I";
     604                 :          0 :     cgi->sigmsg = "Issuer of Assertion unknown.";
     605                 :          0 :     ses->sigres = ZXSIG_NO_SIG;
     606         [ #  # ]:          0 :     if (cf->nosig_fatal) {
     607                 :          0 :       err = "P";
     608                 :          0 :       goto erro;
     609                 :            :     }
     610                 :            :   } else {
     611   [ +  -  +  -  :         20 :     if (a7n->Signature && a7n->Signature->SignedInfo && a7n->Signature->SignedInfo->Reference) {
                   +  - ]
     612                 :         10 :       cf->ctx->guard_seen_n.seen_n = &cf->ctx->guard_seen_p;  /* *** should call zx_reset_ctx? */
     613                 :         10 :       cf->ctx->guard_seen_p.seen_p = &cf->ctx->guard_seen_n;
     614                 :         10 :       ZERO(&refs, sizeof(refs));
     615                 :         10 :       refs.sref = a7n->Signature->SignedInfo->Reference;
     616                 :         10 :       refs.blob = &a7n->gg;
     617                 :         10 :       refs.pop_seen = pop_seen;
     618                 :         10 :       zx_see_elem_ns(cf->ctx, &refs.pop_seen, &a7n->gg);
     619                 :         10 :       ses->sigres = zxsig_validate(cf->ctx, idp_meta->sign_cert, a7n->Signature, 1, &refs);
     620                 :         10 :       zxid_sigres_map(ses->sigres, &cgi->sigval, &cgi->sigmsg);
     621                 :            :     } else {
     622   [ #  #  #  # ]:          0 :       if (cf->msg_sig_ok && !ses->sigres) {
     623                 :          0 :         INFO("Assertion without signature accepted due to message level signature (SimpleSign) %d", 0);
     624                 :            :       } else {
     625         [ #  # ]:          0 :         ERR("SSO warn: assertion not signed. Sigval(%s) %p", STRNULLCHKNULL(cgi->sigval), a7n->Signature);
     626                 :          0 :         cgi->sigval = "N";
     627                 :          0 :         cgi->sigmsg = "Assertion was not signed.";
     628                 :          0 :         ses->sigres = ZXSIG_NO_SIG;
     629         [ #  # ]:          0 :         if (cf->nosig_fatal) {
     630                 :          0 :           err = "P";
     631                 :          0 :           goto erro;
     632                 :            :         }
     633                 :            :       }
     634                 :            :     }
     635                 :            :   }
     636   [ +  -  -  + ]:         10 :   if (cf->sig_fatal && ses->sigres) {
     637                 :          0 :     ERR("Fail SSO due to failed signature sigres=%d", ses->sigres);
     638                 :          0 :     err = "P";
     639                 :          0 :     goto erro;
     640                 :            :   }
     641                 :            :   
     642         [ -  + ]:         10 :   if (zxid_validate_cond(cf, cgi, ses, a7n, zxid_my_ent_id(cf), &ourts, &err))
     643                 :          0 :     goto erro;
     644                 :            :   
     645         [ +  - ]:         10 :   if (cf->log_rely_a7n) {
     646                 :            :     DD("Logging... %d", 0);
     647                 :         10 :     logpath = zxlog_path(cf, issuer, &a7n->ID->g, ZXLOG_RELY_DIR, ZXLOG_A7N_KIND, 1);
     648         [ +  - ]:         10 :     if (logpath) {
     649                 :         10 :       ses->sso_a7n_path = ses->tgt_a7n_path = zx_str_to_c(cf->ctx, logpath);
     650                 :         10 :       ss = zx_easy_enc_elem_sig(cf, &a7n->gg);
     651         [ +  + ]:         10 :       if (zxlog_dup_check(cf, logpath, "SSO assertion")) {
     652         [ -  + ]:          6 :         if (cf->dup_a7n_fatal) {
     653                 :          0 :           err = "C";
     654                 :          0 :           zxlog_blob(cf, cf->log_rely_a7n, logpath, ss, "sp_sso_finalize dup err");
     655                 :          0 :           goto erro;
     656                 :            :         }
     657                 :            :       }
     658                 :         10 :       zxlog_blob(cf, cf->log_rely_a7n, logpath, ss, "sp_sso_finalize");
     659                 :         10 :       zx_str_free(cf->ctx, ss);
     660                 :            :     }
     661                 :            :   }
     662                 :            :   DD("Creating session... %d", 0);
     663                 :         10 :   ses->ssores = 0;
     664                 :         10 :   zxid_put_ses(cf, ses);
     665                 :         10 :   zxid_snarf_eprs_from_ses(cf, ses);  /* Harvest attributes and bootstrap(s) */
     666                 :         10 :   cgi->msg = "SSO completed and session created.";
     667                 :         10 :   cgi->op = '-';  /* Make sure management screen does not try to redispatch. */
     668   [ +  -  +  -  :         10 :   zxid_put_user(cf, &ses->nameid->Format->g, &ses->nameid->NameQualifier->g, &ses->nameid->SPNameQualifier->g, ZX_GET_CONTENT(ses->nameid), 0);
                   +  - ]
     669                 :            :   DD("Logging... %d", 0);
     670         [ +  - ]:         10 :   zxlog(cf, &ourts, &srcts, 0, issuer, 0, &a7n->ID->g, subj,
     671                 :            :         cgi->sigval, "K", "NEWSES", ses->sid, "sesix(%s)", ses->sesix?ses->sesix:"-");
     672   [ +  -  +  - ]:         10 :   zxlog(cf, &ourts, &srcts, 0, issuer, 0, &a7n->ID->g, subj,
     673                 :            :         cgi->sigval, "K", ses->nidfmt?"FEDSSO":"TMPSSO", ses->sesix?ses->sesix:"-", 0);
     674                 :         10 :   D_DEDENT("ssof: ");
     675                 :         10 :   return ZXID_SSO_OK;
     676                 :            : 
     677                 :          0 : erro:
     678                 :          0 :   ERR("SSO fail (%s)", err);
     679                 :          0 :   cgi->msg = "SSO failed. This could be due to signature, timeout, etc., technical failures, or by policy.";
     680   [ #  #  #  #  :          0 :   zxlog(cf, &ourts, &srcts, 0, issuer, 0, a7n?&a7n->ID->g:0, subj,
                   #  # ]
     681                 :            :         cgi->sigval, err, ses->nidfmt?"FEDSSO":"TMPSSO", ses->sesix?ses->sesix:"-", "Error.");
     682                 :          0 :   D_DEDENT("ssof: ");
     683                 :          0 :   return 0;
     684                 :            : }
     685                 :            : 
     686                 :            : /*() Fake a login and generate a session. Used if SSO failure is configured to result
     687                 :            :  * anonymous session.
     688                 :            :  *
     689                 :            :  * cf::  Configuration object, used to determine time slops, potentially memalloc via cf->ctx
     690                 :            :  * cgi:: CGI object. sigval and sigmsg may be set.
     691                 :            :  * ses:: Session object. Will be modified according to new session created from the SSO assertion.
     692                 :            :  * return:: 0 for failure, otherwise some success code such as ZXID_SSO_OK */
     693                 :            : 
     694                 :            : /* Called by:  zxid_sp_dig_sso_a7n */
     695                 :            : int zxid_sp_anon_finalize(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses)
     696                 :          1 : {
     697                 :          1 :   D_INDENT("anon_ssof: ");
     698                 :          1 :   cgi->sigval = "N";
     699                 :          1 :   cgi->sigmsg = "Anonymous login. No signature.";
     700                 :          1 :   ses->sigres = ZXSIG_NO_SIG;
     701                 :          1 :   ses->a7n = 0;
     702                 :          1 :   ses->rs = cgi->rs;
     703                 :          1 :   ses->nameid = 0;
     704                 :          1 :   ses->nid = "-";
     705                 :          1 :   ses->nidfmt = 0;
     706                 :          1 :   ses->sesix = 0;
     707                 :            :   
     708   [ -  +  #  # ]:          1 :   D("SSO FAIL: ANON_OK. Creating session... %p", ses);
     709                 :            :   
     710                 :          1 :   zxid_put_ses(cf, ses);
     711                 :          1 :   zxid_snarf_eprs_from_ses(cf, ses);  /* Harvest attributes and bootstrap(s) */
     712                 :          1 :   cgi->msg = "SSO Failure treated as anonymous login and session created.";
     713                 :          1 :   cgi->op = '-';  /* Make sure management screen does not try to redispatch. */
     714                 :            :   /*zxid_put_user(cf, ses->nameid->Format, ses->nameid->NameQualifier, ses->nameid->SPNameQualifier, ZX_GET_CONTENT(ses->nameid), 0);*/
     715                 :          1 :   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, cgi->sigval, "K", "TMPSSO", "-", 0);
     716                 :          1 :   D_DEDENT("anon_ssof: ");
     717                 :          1 :   return ZXID_SSO_OK;
     718                 :            : }
     719                 :            : 
     720                 :            : /*() Authentication Service Client
     721                 :            :  * See also: zxid_idp_as_do()
     722                 :            :  */
     723                 :            : 
     724                 :            : /* Called by:  zxid_as_call */
     725                 :            : int zxid_as_call_ses(zxid_conf* cf, zxid_entity* idp_meta, zxid_cgi* cgi, zxid_ses* ses)
     726                 :         17 : {
     727                 :            :   int len;
     728                 :            :   struct zx_root_s* r;
     729                 :            :   struct zx_e_Body_s* body;
     730                 :            : #if 0
     731                 :            :   struct zx_md_ArtifactResolutionService_s* ar_svc;
     732                 :            : #else
     733                 :            :   struct zx_md_SingleLogoutService_s* ar_svc;
     734                 :            : #endif
     735                 :            :   struct zx_as_SASLResponse_s* res;
     736                 :            :   char* buf;
     737                 :            :   char* b64;
     738                 :            :   char* p;
     739                 :         17 :   D_INDENT("as_call: ");
     740                 :            : 
     741   [ +  -  +  -  :         17 :   if (!cf || !cgi || !ses || !cgi->uid || !cgi->pw) {
          +  -  +  -  -  
                      + ]
     742                 :          0 :     ERR("Missing user, password, or mandatory argument cgi=%p (caller programming error)", cgi);
     743                 :          0 :     D_DEDENT("as_call: ");
     744                 :          0 :     return 0;
     745                 :            :   }
     746                 :            :   
     747   [ +  -  +  -  :         17 :   if (!idp_meta || !idp_meta->eid || !idp_meta->ed->IDPSSODescriptor) {
                   -  + ]
     748   [ #  #  #  # ]:          0 :     ERR("Entity(%s) does not have IdP SSO Descriptor (metadata problem)", idp_meta?STRNULLCHKQ(idp_meta->eid):"-");
     749   [ #  #  #  # ]:          0 :     zxlog(cf, 0,0,0,0,0,0,0, "N", "B", "ERR", 0, "No IDPSSODescriptor eid(%*s)", idp_meta?STRNULLCHKQ(idp_meta->eid):"-");
     750                 :          0 :     D_DEDENT("as_call: ");
     751                 :          0 :     return 0;
     752                 :            :   }
     753                 :            : 
     754                 :            : #if 0
     755                 :            :   for (ar_svc = idp_meta->ed->IDPSSODescriptor->ArtifactResolutionService;
     756                 :            :        ar_svc && ar_svc->gg.g.tok == zx_md_ArtifactResolutionService_ELEM;
     757                 :            :        ar_svc = (struct zx_md_ArtifactResolutionService_s*)ar_svc->gg.g.n)
     758                 :            :     if (ar_svc->Binding  && !memcmp(SAML2_SOAP, ar_svc->Binding->s, ar_svc->Binding->len)
     759                 :            :         /*&& ar_svc->index && !memcmp(end_pt_ix, ar_svc->index->s, ar_svc->index->len)*/
     760                 :            :         && ar_svc->Location)
     761                 :            :       break;
     762                 :            : #else
     763                 :            :   /* *** Kludge: We use the SLO SOAP endpoint for AS. ArtifactResolution might be more natural. */
     764                 :         17 :   for (ar_svc = idp_meta->ed->IDPSSODescriptor->SingleLogoutService;
     765   [ +  -  +  - ]:         51 :        ar_svc && ar_svc->gg.g.tok == zx_md_SingleLogoutService_ELEM;
     766                 :         17 :        ar_svc = (struct zx_md_SingleLogoutService_s*)ar_svc->gg.g.n)
     767   [ +  -  +  +  :         34 :     if (ar_svc->Binding  && !memcmp(SAML2_SOAP, ar_svc->Binding->g.s, ar_svc->Binding->g.len)
                   +  - ]
     768                 :            :         /*&& ar_svc->index && !memcmp(end_pt_ix, ar_svc->index->s, ar_svc->index->len)*/
     769                 :            :         && ar_svc->Location)
     770                 :         17 :       break;
     771                 :            : #endif
     772         [ -  + ]:         17 :   if (!ar_svc) {
     773                 :          0 :     ERR("Entity(%s) does not have any IdP Artifact Resolution Service with " SAML2_SOAP " binding (metadata problem)", idp_meta->eid);
     774                 :          0 :     zxlog(cf, 0,0,0,0,0,0,0,"N","B","ERR",0,"No Artifact Resolution Svc eid(%s)", idp_meta->eid);
     775                 :          0 :     D_DEDENT("as_call: ");
     776                 :          0 :     return 0;
     777                 :            :   }
     778                 :            : 
     779                 :         17 :   len = 1+strlen(cgi->uid)+1+strlen(cgi->pw)+1;
     780                 :         17 :   p = buf = ZX_ALLOC(cf->ctx, len);
     781                 :         17 :   *p++ = 0;
     782                 :         17 :   strcpy(p, cgi->uid);
     783                 :         17 :   p += strlen(cgi->uid) + 1;
     784                 :         17 :   strcpy(p, cgi->pw);
     785                 :            :   
     786                 :         17 :   b64 = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_LEN(len)+1);
     787                 :         17 :   p = base64_fancy_raw(buf, len, b64, std_basis_64, 1<<31, 0, 0, '=');
     788                 :         17 :   *p = 0;
     789                 :         17 :   ZX_FREE(cf->ctx, buf);
     790                 :            :   
     791                 :         17 :   body = zx_NEW_e_Body(cf->ctx,0);
     792                 :         17 :   body->SASLRequest = zx_NEW_as_SASLRequest(cf->ctx, &body->gg);
     793                 :         17 :   body->SASLRequest->mechanism = zx_dup_attr(cf->ctx, &body->SASLRequest->gg, zx_mechanism_ATTR, "PLAIN");
     794                 :         17 :   body->SASLRequest->Data = zx_ref_len_elem(cf->ctx, &body->SASLRequest->gg, zx_as_Data_ELEM, p-b64, b64);
     795                 :         17 :   r = zxid_soap_call_hdr_body(cf, &ar_svc->Location->g, 0, body);
     796                 :            :   /* *** free the body */
     797                 :            :   
     798   [ +  -  +  -  :         17 :   if (!r || !r->Envelope || !r->Envelope->Body || !(res = r->Envelope->Body->SASLResponse)) {
             +  -  -  + ]
     799                 :          0 :     ERR("Autentication Service call failed idp(%s). Missing response.", idp_meta->eid);
     800                 :          0 :     zxlog(cf, 0,0,0,0,0,0,0, "N", "B", "ERR", 0, "Missing response eid(%s)", idp_meta->eid);
     801                 :          0 :     D_DEDENT("as_call: ");
     802                 :          0 :     return 0;
     803                 :            :   }
     804                 :            :   
     805   [ +  -  +  -  :         17 :   if (!res->Status || !res->Status->code || !res->Status->code->g.len || !res->Status->code->g.s) {
             +  -  -  + ]
     806                 :          0 :     ERR("Autentication Service call failed idp(%s). Missing Status code.", idp_meta->eid);
     807                 :          0 :     zxlog(cf, 0,0,0,0,0,0,0, "N", "B", "ERR", 0, "Missing Status code eid(%s)", idp_meta->eid);
     808                 :          0 :     D_DEDENT("as_call: ");
     809                 :          0 :     return 0;
     810                 :            :   }
     811                 :            : 
     812   [ +  +  +  -  :         17 :   if (res->Status->code->g.len != 2
                   -  + ]
     813                 :            :       || res->Status->code->g.s[0]!='O' || res->Status->code->g.s[1]!='K') {  /* "OK" */
     814                 :          2 :     ERR("Autentication Service call failed idp(%s). Status code(%.*s).", idp_meta->eid, res->Status->code->g.len, res->Status->code->g.s);
     815                 :          2 :     zxlog(cf, 0,0,0,0,0,0,0, "N", "B", "ERR", 0, "Missing Status code(%.*s) eid(%s)", res->Status->code->g.len, res->Status->code->g.s, idp_meta->eid);
     816                 :          2 :     D_DEDENT("as_call: ");
     817                 :          2 :     return 0;
     818                 :            :   }
     819                 :            :   
     820                 :         15 :   ses->sigres = ZXSIG_NO_SIG;
     821                 :         15 :   ses->a7n = 0;
     822                 :         15 :   ses->nameid = 0;
     823                 :         15 :   ses->nid = "-";
     824                 :         15 :   ses->nidfmt = 0;
     825                 :         15 :   ses->sesix = 0;
     826                 :            :   
     827   [ +  +  -  + ]:         15 :   D("AuthenSvc OK. Creating session... %p", ses);
     828                 :            :   
     829                 :         15 :   zxid_put_ses(cf, ses);
     830                 :         15 :   zxid_ses_to_pool(cf, ses);  /* Process SSO a7n, applying NEED, WANT, and INMAP */
     831                 :         15 :   zxid_snarf_eprs(cf, ses, res->EndpointReference);
     832                 :            :   
     833                 :            :   /* *** free r */
     834                 :         15 :   D_DEDENT("as_call: ");
     835                 :         15 :   return ZXID_SSO_OK;
     836                 :            : }
     837                 :            : 
     838                 :            : /* Called by:  zxcall_main */
     839                 :            : zxid_ses* zxid_as_call(zxid_conf* cf, zxid_entity* idp_meta, const char* user, const char* pw)
     840                 :         17 : {
     841                 :         17 :   zxid_ses* ses = zxid_alloc_ses(cf);
     842                 :            :   zxid_cgi cgi;
     843                 :         17 :   ZERO(&cgi, sizeof(cgi));
     844                 :         17 :   cgi.uid = (char*)user;
     845                 :         17 :   cgi.pw = (char*)pw;
     846                 :            :   
     847         [ +  + ]:         17 :   if (!zxid_as_call_ses(cf, idp_meta, &cgi, ses)) {
     848                 :          2 :     ZX_FREE(cf->ctx, ses);
     849                 :          2 :     return 0;
     850                 :            :   }
     851                 :         15 :   return ses;
     852                 :            : }
     853                 :            : 
     854                 :            : /* EOF  --  zxidsso.c */

Generated by: LCOV version 1.9