LCOV - code coverage report
Current view: top level - zxid - zxidpsso.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 293 447 65.5 %
Date: 2010-12-19 Functions: 14 14 100.0 %
Branches: 263 657 40.0 %

           Branch data     Line data    Source code
       1                 :            : /* zxidpsso.c  -  Handwritten functions for implementing Single Sign-On logic on IdP
       2                 :            :  * Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2008-2009 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       4                 :            :  * This is confidential unpublished proprietary source code of the author.
       5                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       6                 :            :  * Distribution prohibited unless authorized in writing.
       7                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       8                 :            :  * $Id: zxidpsso.c,v 1.16 2010-01-08 02:10:09 sampo Exp $
       9                 :            :  *
      10                 :            :  * 14.11.2008, created --Sampo
      11                 :            :  * 4.9.2009,   added persistent nameid support --Sampo
      12                 :            :  * 24.11.2009, fixed handling of transient nameid --Sampo
      13                 :            :  * 12.2.2010,  added locking to lazy loading --Sampo
      14                 :            :  *
      15                 :            :  * See also: http://hoohoo.ncsa.uiuc.edu/cgi/interface.html (CGI specification)
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "platform.h"  /* for dirent.h */
      19                 :            : 
      20                 :            : #include <sys/stat.h>
      21                 :            : #include <errno.h>
      22                 :            : 
      23                 :            : #include "errmac.h"
      24                 :            : #include "zxid.h"
      25                 :            : #include "zxidpriv.h"
      26                 :            : #include "zxidutil.h"
      27                 :            : #include "zxidconf.h"
      28                 :            : #include "saml2.h"
      29                 :            : #include "wsf.h"
      30                 :            : #include "c/zxidvers.h"
      31                 :            : #include "c/zx-const.h"
      32                 :            : #include "c/zx-ns.h"
      33                 :            : #include "c/zx-data.h"
      34                 :            : 
      35                 :            : /*() Helper function to sign, if needed, and log the issued assertion.
      36                 :            :  * Checks for Assertion ID duplicate and returns 0 on
      37                 :            :  * failure (i.e. duplicate), 1 on success. */
      38                 :            : 
      39                 :            : /* Called by:  zxid_add_fed_tok2epr, zxid_idp_sso x3, zxid_imreq, zxid_map_val_ss */
      40                 :            : int zxid_anoint_a7n(zxid_conf* cf, int sign, zxid_a7n* a7n, struct zx_str* issued_to, const char* lk, const char* uid)
      41                 :        815 : {
      42                 :            :   X509* sign_cert;
      43                 :            :   EVP_PKEY*  sign_pkey;
      44                 :            :   struct zxsig_ref refs;
      45                 :            :   struct zx_str* ss;
      46                 :            :   struct zx_str* logpath;
      47                 :            :   struct timeval ourts;
      48                 :        815 :   GETTIMEOFDAY(&ourts, 0);
      49                 :            :   
      50         [ +  - ]:        815 :   if (sign) {
      51                 :        815 :     ZERO(&refs, sizeof(refs));
      52                 :        815 :     refs.id = &a7n->ID->g;
      53                 :        815 :     refs.canon = zx_easy_enc_elem_sig(cf, &a7n->gg);
      54         [ +  - ]:        815 :     if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey,"use sign cert anoint a7n")) {
      55                 :        815 :       a7n->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey);
      56                 :        815 :       zx_add_kid_after_sa_Issuer(&a7n->gg, &a7n->Signature->gg);
      57                 :            :     }
      58                 :        815 :     zx_str_free(cf->ctx, refs.canon);
      59                 :            :   }
      60                 :            :   
      61                 :            :   /* Log the issued a7n */
      62                 :            : 
      63         [ +  - ]:        815 :   if (cf->loguser)
      64   [ +  -  -  +  :        815 :     zxlogusr(cf, uid, &ourts, &ourts, 0, issued_to, 0, &a7n->ID->g,
          #  #  #  #  #  
          #  #  #  #  #  
                   +  - ]
      65                 :            :              (ZX_GET_CONTENT(a7n->Subject->NameID)
      66                 :            :               ?ZX_GET_CONTENT(a7n->Subject->NameID)
      67                 :            :               :(zx_dup_str(cf->ctx, (a7n->Subject->EncryptedID?"ENC":"-")))),
      68                 :            :              sign?"U":"N", "K", lk, "-", 0);
      69                 :            : 
      70   [ +  -  -  +  :        815 :   zxlog(cf, &ourts, &ourts, 0, issued_to, 0, &a7n->ID->g,
          #  #  #  #  #  
          #  #  #  #  #  
                   +  - ]
      71                 :            :         (ZX_GET_CONTENT(a7n->Subject->NameID)
      72                 :            :          ?ZX_GET_CONTENT(a7n->Subject->NameID)
      73                 :            :          :(zx_dup_str(cf->ctx, (a7n->Subject->EncryptedID?"ENC":"-")))),
      74                 :            :         sign?"U":"N", "K", lk, "-", 0);
      75                 :            :   
      76         [ +  - ]:        815 :   if (cf->log_issue_a7n) {
      77                 :        815 :     logpath = zxlog_path(cf, issued_to, &a7n->ID->g, ZXLOG_ISSUE_DIR, ZXLOG_A7N_KIND, 1);
      78         [ +  - ]:        815 :     if (logpath) {
      79                 :        815 :       ss = zx_easy_enc_elem_sig(cf, &a7n->gg);
      80         [ -  + ]:        815 :       if (zxlog_dup_check(cf, logpath, "IdP POST Assertion")) {
      81                 :          0 :         ERR("Duplicate Assertion ID(%.*s)", a7n->ID->g.len, a7n->ID->g.s);
      82         [ #  # ]:          0 :         if (cf->dup_a7n_fatal) {
      83                 :          0 :           ERR("FATAL (by configuration): Duplicate Assertion ID(%.*s)", a7n->ID->g.len, a7n->ID->g.s);
      84                 :          0 :           zxlog_blob(cf, 1, logpath, ss, "anoint_a7n dup");
      85                 :          0 :           zx_str_free(cf->ctx, ss);
      86                 :          0 :           zx_str_free(cf->ctx, logpath);
      87                 :          0 :           return 0;
      88                 :            :         }
      89                 :            :       }
      90                 :        815 :       zxlog_blob(cf, 1, logpath, ss, "anoint_a7n");
      91                 :        815 :       zx_str_free(cf->ctx, logpath);
      92                 :        815 :       zx_str_free(cf->ctx, ss);
      93                 :            :     }
      94                 :            :   }
      95                 :        815 :   return 1;
      96                 :            : }
      97                 :            : 
      98                 :            : /*() Helper function to sign, if needed, and log the issued response.
      99                 :            :  * Checks for message ID duplicate and returns 0 on failure (i.e. duplicate),
     100                 :            :  * or the canonicalized response message string on success. This string
     101                 :            :  * may be useful for caller to send further and should be freed by the caller. */
     102                 :            : 
     103                 :            : /* Called by:  zxid_idp_sso x4, zxid_ssos_anreq */
     104                 :            : struct zx_str* zxid_anoint_sso_resp(zxid_conf* cf, int sign, struct zx_sp_Response_s* resp, struct zx_sp_AuthnRequest_s* ar)
     105                 :          6 : {
     106                 :            :   X509* sign_cert;
     107                 :            :   EVP_PKEY* sign_pkey;
     108                 :            :   zxid_a7n* a7n;
     109                 :            :   struct zxsig_ref refs;
     110                 :            :   struct zx_str* ss;
     111                 :            :   struct zx_str* logpath;
     112                 :            :   struct timeval ourts;
     113                 :          6 :   GETTIMEOFDAY(&ourts, 0);
     114                 :            :   
     115         [ -  + ]:          6 :   if (sign) {
     116                 :          0 :     ZERO(&refs, sizeof(refs));
     117                 :          0 :     refs.id = &resp->ID->g;
     118                 :          0 :     refs.canon = zx_easy_enc_elem_sig(cf, &resp->gg);
     119         [ #  # ]:          0 :     if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert,&sign_pkey,"use sign cert anoint resp")) {
     120                 :          0 :       resp->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey);
     121                 :          0 :       zx_add_kid_after_sa_Issuer(&resp->gg, &resp->Signature->gg);
     122                 :            :     }
     123                 :          0 :     zx_str_free(cf->ctx, refs.canon);
     124                 :            :   }
     125                 :            :   
     126                 :            :   /* Log the issued Response */
     127                 :            :   
     128                 :          6 :   a7n = resp->Assertion;
     129   [ -  +  -  +  :          6 :   zxlog(cf, &ourts, &ourts, 0, ZX_GET_CONTENT(ar->Issuer), &resp->ID->g,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  -  
          +  #  #  +  -  
             +  -  +  - ]
     130                 :            :         a7n&&a7n->ID?&a7n->ID->g:zx_dup_str(cf->ctx, "-"),
     131                 :            :         (a7n
     132                 :            :          ?(ZX_GET_CONTENT(a7n->Subject->NameID)
     133                 :            :            ?ZX_GET_CONTENT(a7n->Subject->NameID)
     134                 :            :            :(zx_dup_str(cf->ctx, (a7n->Subject->EncryptedID?"ENC":"-"))))
     135                 :            :          :zx_dup_str(cf->ctx,"-")),
     136                 :            :         sign?"U":"N", "K", "SSORESP", "-", 0);
     137                 :            : 
     138                 :          6 :   ss = zx_easy_enc_elem_opt(cf, &resp->gg);
     139                 :            : 
     140         [ +  - ]:          6 :   if (cf->log_issue_msg) {
     141   [ +  -  +  -  :          6 :     logpath = zxlog_path(cf, ZX_GET_CONTENT(ar->Issuer), &resp->ID->g, ZXLOG_ISSUE_DIR, ZXLOG_MSG_KIND,1);
                   +  - ]
     142         [ +  - ]:          6 :     if (logpath) {
     143         [ -  + ]:          6 :       if (zxlog_dup_check(cf, logpath, "IdP POST Response")) {
     144                 :          0 :         ERR("Duplicate Response ID(%.*s)", resp->ID->g.len, resp->ID->g.s);
     145         [ #  # ]:          0 :         if (cf->dup_msg_fatal) {
     146                 :          0 :           ERR("FATAL (by configuration): Duplicate Response ID(%.*s)", resp->ID->g.len, resp->ID->g.s);
     147                 :          0 :           zxlog_blob(cf, 1, logpath, ss, "anoint_sso_resp dup");
     148                 :          0 :           zx_str_free(cf->ctx, ss);
     149                 :          0 :           zx_str_free(cf->ctx, logpath);
     150                 :          0 :           return 0;
     151                 :            :         }
     152                 :            :       }
     153                 :          6 :       zxlog_blob(cf, 1, logpath, ss, "anoint_sso_resp");
     154                 :          6 :       zx_str_free(cf->ctx, logpath);
     155                 :            :     }
     156                 :            :   }
     157                 :          6 :   return ss;
     158                 :            : }
     159                 :            : 
     160                 :            : #define ZXID_ADD_BS_LVL_LIM 2  /* 2=only add full bootstraps on SSO. Only add di there after. */
     161                 :            : 
     162                 :            : /*() Process .bs directory. See also zxid_di_query() */
     163                 :            : 
     164                 :            : /* Called by:  zxid_idp_as_do x2, zxid_mk_usr_a7n_to_sp x2 */
     165                 :            : void zxid_gen_boots(zxid_conf* cf, zxid_ses* ses, struct zx_sa_AttributeStatement_s* father, char* path, int bs_lvl)
     166                 :        306 : {
     167                 :        306 :   struct timeval srcts = {0,501000};
     168                 :            :   struct zx_sa_Attribute_s* at;
     169                 :            :   zxid_epr* epr;
     170                 :            :   struct zx_root_s* r;
     171                 :            :   struct zx_str* ss;
     172                 :            :   DIR* dir;
     173                 :            :   struct dirent * de;
     174                 :            :   char mdpath[ZXID_MAX_BUF];
     175                 :            :   char logop[8];
     176                 :            :   char* epr_buf;
     177                 :            :   int epr_len, is_di, ret;
     178                 :            : 
     179                 :        306 :   D_INDENT("gen_bs: ");
     180                 :            : 
     181         [ +  + ]:        306 :   if (!bs_lvl) {
     182   [ +  -  -  + ]:        152 :     D("bs_lvl=%d: nothing to add", bs_lvl);
     183                 :        152 :     D_DEDENT("gen_bs: ");
     184                 :        152 :     return;  /* Discovery EPRs do not need any bootstraps. */
     185                 :            :   }
     186                 :            :   
     187                 :        154 :   name_from_path(mdpath, sizeof(mdpath), "%s" ZXID_DIMD_DIR, cf->path);
     188   [ +  +  -  + ]:        154 :   D("Looking for service metadata in dir(%s) bs_lvl=%d", mdpath, bs_lvl);
     189                 :            :   
     190                 :        154 :   dir = opendir(path);
     191         [ +  + ]:        154 :   if (!dir) {
     192                 :          2 :     perror("opendir to find bootstraps");
     193                 :          2 :     ERR("Opening bootstrap directory failed path(%s)", path);
     194                 :          2 :     D_DEDENT("gen_bs: ");
     195                 :          2 :     return;
     196                 :            :   }
     197                 :            :   
     198         [ +  + ]:       1596 :   while (de = readdir(dir)) {
     199   [ +  -  -  + ]:       1292 :     D("Consider bs(%s%s)", path, de->d_name);
     200                 :            :     
     201         [ +  + ]:       1292 :     if (de->d_name[strlen(de->d_name)-1] == '~')  /* Ignore backups from hand edited EPRs. */
     202                 :        152 :       continue;
     203         [ +  + ]:       1140 :     if (de->d_name[0] == '.')  /* Ignore hidden files. */
     204                 :        532 :       continue;
     205                 :            :     
     206                 :            :     /* Probable enough, read and parse EPR so we can continue examination. */
     207                 :            :     
     208                 :        608 :     epr_buf = read_all_alloc(cf->ctx, "find_bs_svcmd", 1, &epr_len, "%s/%s", mdpath, de->d_name);
     209         [ +  + ]:        608 :     if (!epr_buf) {
     210                 :        152 :       ERR("User's (%s) bootstrap(%s) lacks service metadata registration. Reject. Consider using zxcot -e ... | zxcot -bs. See zxid-idp.pd for further information.", ses->uid, de->d_name);
     211                 :        152 :       ZX_FREE(cf->ctx, epr_buf);
     212                 :        152 :       continue;
     213                 :            :     }
     214                 :        456 :     r = zx_dec_zx_root(cf->ctx, epr_len, epr_buf, "gen boots");
     215         [ -  + ]:        456 :     if (!r) {
     216                 :          0 :       ERR("Failed to XML parse epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
     217                 :          0 :       ZX_FREE(cf->ctx, epr_buf);
     218                 :          0 :       continue;
     219                 :            :     }
     220                 :            :     /* *** add ID-WSF 1.1 handling */
     221                 :        456 :     epr = r->EndpointReference;
     222                 :        456 :     ZX_FREE(cf->ctx, r);
     223                 :            : 
     224   [ +  -  +  -  :        456 :     if (!epr || !epr->Metadata || !ZX_SIMPLE_ELEM_CHK(epr->Metadata->ServiceType)) {
          +  -  +  -  +  
          -  +  -  +  -  
                   -  + ]
     225                 :          0 :       ERR("No EPR, corrupt EPR, or missing <Metadata> %p or <ServiceType>. epr_buf(%.*s) file(%s)", epr->Metadata, epr_len, epr_buf, de->d_name);
     226                 :          0 :       ZX_FREE(cf->ctx, epr_buf);
     227                 :          0 :       continue;
     228                 :            :     }
     229   [ +  -  +  -  :        456 :     ss = ZX_GET_CONTENT(epr->Metadata->ServiceType);
                   +  - ]
     230   [ +  -  +  + ]:        456 :     is_di = ss? !memcmp(ss->s, XMLNS_DISCO_2_0, ss->len) : 0;
     231   [ +  -  +  -  :        456 :     D("FOUND BOOTSTRAP url(%.*s) is_di=%d", ZX_GET_CONTENT_LEN(epr->Address), ZX_GET_CONTENT_S(epr->Address), is_di);
          +  -  +  -  +  
          -  +  -  +  -  
                   -  + ]
     232                 :            :     
     233         [ +  + ]:        456 :     if (is_di) {
     234                 :         76 :       ret = zxid_add_fed_tok2epr(cf, ses, epr, 0, logop); /* recurse, di tail */
     235         [ +  + ]:        380 :     } else if (bs_lvl > cf->bootstrap_level) {
     236   [ +  -  -  + ]:        190 :       D("No further bootstraps generated due to boostrap_level=%d (except di boostraps)", bs_lvl);
     237                 :        190 :       ZX_FREE(cf->ctx, epr_buf);
     238                 :        190 :       continue;
     239                 :            :     } else
     240                 :        190 :       ret = zxid_add_fed_tok2epr(cf, ses, epr, bs_lvl+1, logop); /* recurse */
     241   [ +  -  -  + ]:        266 :     D("bs_lvl=%d: adding logop(%s)", bs_lvl, logop);
     242         [ +  + ]:        266 :     if (!ret)
     243                 :        152 :       goto next_file;
     244                 :            :     
     245   [ +  -  +  -  :        114 :     D("ADD BOOTSTRAP url(%.*s) is_di=%d", ZX_GET_CONTENT_LEN(epr->Address), ZX_GET_CONTENT_S(epr->Address), is_di);
          +  -  +  -  +  
          -  +  -  +  -  
                   -  + ]
     246                 :        114 :     father->Attribute = at = zxid_mk_sa_attribute(cf, &father->gg, WSF20_DI_RO, 0, 0);
     247                 :        114 :     ZX_ADD_KID(at->AttributeValue, EndpointReference, epr);
     248                 :            :     
     249                 :        114 :     zxlog(cf, 0, &srcts, 0, 0, 0, 0 /*a7n->ID*/, 0 /*nameid->gg.content*/,"N","K", logop, ses->uid, "gen_bs");
     250                 :            :     
     251                 :       1444 :   next_file:
     252                 :            :     continue;
     253                 :            :   }
     254                 :            :   
     255                 :        152 :   closedir(dir);
     256                 :        152 :   D_DEDENT("gen_bs: ");
     257                 :            : }
     258                 :            : 
     259                 :            : /* Called by:  zxid_add_ldif_attrs, zxid_mk_usr_a7n_to_sp x3 */
     260                 :            : static void zxid_add_mapped_attr(zxid_conf* cf, zxid_ses* ses, zxid_entity* meta, struct zx_elem_s* father, char* lk, struct zxid_map* sp_aamap, const char* name, const char* val)
     261                 :       2876 : {
     262                 :            :   struct zxid_map* map;
     263                 :       2876 :   map = zxid_find_map(sp_aamap, name);
     264         [ +  - ]:       2876 :   if (!map)
     265                 :       2876 :     map = zxid_find_map(cf->aamap, name);
     266   [ +  -  +  + ]:       5751 :   if (map && map->rule != ZXID_MAP_RULE_DEL) {
     267   [ +  +  -  + ]:       2875 :     D("%s: ATTR(%s)=VAL(%s)", lk, name, val);
     268   [ +  -  +  +  :       2875 :     if (map->dst && *map->dst && map->src && map->src[0] != '*')
             +  -  +  - ]
     269                 :        136 :       name = map->dst;
     270                 :       2875 :     zxid_mk_sa_attribute_ss(cf, father, name, 0, zxid_map_val(cf, ses, meta, map, name, val));
     271                 :            :   } else {
     272   [ -  +  #  # ]:          1 :     D("%s: Attribute(%s) filtered out either by del rule in aamap, or does not match aamap %p", lk, name, map);
     273                 :            :   }
     274                 :       2876 : }
     275                 :            : 
     276                 :            : /*() Parse LDIF format and insert attributes to linked list. Return new head of the list.
     277                 :            :  * The input is temporarily modified and then restored. Do not pass const string. */
     278                 :            : 
     279                 :            : /* Called by:  zxid_read_ldif_attrs */
     280                 :            : static void zxid_add_ldif_attrs(zxid_conf* cf, zxid_ses* ses, zxid_entity* meta, struct zx_elem_s* father, char* p, char* lk, struct zxid_map* sp_aamap)
     281                 :        272 : {
     282                 :            :   char* name;
     283                 :            :   char* val;
     284                 :            : 
     285         [ +  - ]:       2737 :   for (; p; ++p) {
     286                 :       2737 :     name = p;
     287                 :       2737 :     p = strstr(p, ": ");
     288         [ +  + ]:       2737 :     if (!p)
     289                 :        272 :       break;
     290                 :       2465 :     *p = 0;
     291                 :       2465 :     val = p+2;
     292                 :       2465 :     p = strchr(val, '\n');  /* *** parsing LDIF is fragile if values are multiline */
     293         [ +  - ]:       2465 :     if (p)
     294                 :       2465 :       *p = 0;
     295                 :            :     
     296                 :       2465 :     zxid_add_mapped_attr(cf, ses, meta, father, lk, sp_aamap, name, val);
     297                 :            :     
     298                 :       2465 :     val[-2] = ':'; /* restore */
     299         [ -  + ]:       2465 :     if (p)
     300                 :       2465 :       *p = '\n';
     301                 :            :     else
     302                 :          0 :       break;
     303                 :            :   }
     304                 :        272 : }
     305                 :            : 
     306                 :            : /*() Read Attribute Authority Map */
     307                 :            : 
     308                 :            : /* Called by:  zxid_mk_usr_a7n_to_sp x2 */
     309                 :            : static struct zxid_map* zxid_read_map(zxid_conf* cf, const char* sp_name_buf, const char* mapname)
     310                 :        176 : {
     311                 :            :   char* p;
     312                 :        176 :   char* buf = read_all_alloc(cf->ctx, "read_aamap", 0, 0, "%s" ZXID_UID_DIR ".all/%s/.cf", cf->path,sp_name_buf);
     313         [ +  + ]:        176 :   if (!buf)
     314                 :        132 :     return 0;
     315                 :         44 :   p = strstr(buf, mapname);
     316         [ -  + ]:         44 :   if (!p) {
     317                 :          0 :     ERR(".cf file does not contain AAMAP directive buf(%s)", buf);
     318                 :          0 :     return 0;
     319                 :            :   }
     320                 :         44 :   p += strlen(mapname);
     321                 :         44 :   return zxid_load_map(cf, 0, p);
     322                 :            : }
     323                 :            : 
     324                 :            : /* Called by:  zxid_mk_usr_a7n_to_sp x4 */
     325                 :            : static void zxid_read_ldif_attrs(zxid_conf* cf, zxid_ses* ses, zxid_entity* meta, const char* sp_name_buf, const char* uid, struct zxid_map* sp_aamap, struct zx_sa_AttributeStatement_s* at_stmt)
     326                 :        548 : {
     327                 :            :   char* buf = read_all_alloc(cf->ctx, "read_ldif_attrs", 0, 0,
     328                 :        548 :                              "%s" ZXID_UID_DIR "%s/%s/.at", cf->path, uid, sp_name_buf);
     329         [ +  + ]:        548 :   if (buf)
     330                 :        272 :     zxid_add_ldif_attrs(cf, ses, meta, &at_stmt->gg, buf, "read_ldif_attrs", sp_aamap);
     331                 :        548 : }
     332                 :            : 
     333                 :            : /*(i) Construct an assertion given user's attribute and bootstrap configuration.
     334                 :            :  * This involves adding attributes in user's .bs/.at, SP specific .at, as well as
     335                 :            :  * .all/.bs/.at and .all's SP specific attributes. The attributes are filtered
     336                 :            :  * and converted according to global and SP specific AAMAP.
     337                 :            :  * Finally the bootstrap EPRs are added.
     338                 :            :  *
     339                 :            :  * bs_lvl:: 0: DI (do not add any bs), 1: add all bootstraps at sso level,
     340                 :            :  *     <= cf->bootstrap_level: add all boostraps, > cf->bootstrap_level: only add di BS. */
     341                 :            : 
     342                 :            : /* Called by:  a7n_test, zxid_add_fed_tok2epr, zxid_imreq, zxid_sso_issue_a7n */
     343                 :            : zxid_a7n* zxid_mk_usr_a7n_to_sp(zxid_conf* cf, zxid_ses* ses, zxid_nid* nameid, zxid_entity* sp_meta, const char* sp_name_buf, int bs_lvl)
     344                 :        137 : {
     345                 :            :   struct zxid_map* sp_aamap;
     346                 :            :   zxid_a7n* a7n;
     347                 :            :   struct zx_sa_AttributeStatement_s* at_stmt;
     348                 :            :   char dir[ZXID_MAX_DIR];
     349                 :            : 
     350                 :        137 :   D_INDENT("mka7n: ");
     351   [ +  +  -  + ]:        137 :   D("sp_eid(%s)", sp_meta->eid);
     352                 :            : 
     353         [ +  + ]:        137 :   if (!cf->aamap)
     354                 :         39 :     cf->aamap = zxid_read_map(cf, ".bs", "AAMAP=");
     355         [ +  + ]:        137 :   if (!cf->aamap)
     356                 :          1 :     cf->aamap = zxid_load_map(cf, 0, ZXID_DEFAULT_IDP_AAMAP);
     357                 :        137 :   sp_aamap = zxid_read_map(cf, sp_name_buf, "AAMAP=");
     358                 :            : 
     359                 :        137 :   at_stmt = zx_NEW_sa_AttributeStatement(cf->ctx, 0);
     360                 :        137 :   at_stmt->Attribute = zxid_mk_sa_attribute(cf, &at_stmt->gg, "zxididp", 0, ZXID_REL " " ZXID_COMPILE_DATE);
     361                 :            : 
     362         [ +  - ]:        137 :   a7n = zxid_mk_a7n(cf,
     363                 :            :                     zx_dup_str(cf->ctx, sp_meta->eid),
     364                 :            :                     zxid_mk_subj(cf, 0, sp_meta, nameid),
     365                 :            :                     ses ? zxid_mk_an_stmt(cf, ses, 0, sp_meta->eid) : 0,
     366                 :            :                     at_stmt);
     367                 :            : 
     368   [ +  -  +  - ]:        137 :   if (cf->fedusername_suffix && cf->fedusername_suffix[0]) {
     369   [ +  -  +  -  :        137 :     snprintf(dir, sizeof(dir), "%.*s@%s", ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid), cf->fedusername_suffix);
          +  -  +  -  +  
                -  +  - ]
     370                 :        137 :     dir[sizeof(dir)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
     371                 :        137 :     zxid_add_mapped_attr(cf, ses, sp_meta, &at_stmt->gg, "mk_usr_a7n_to_sp", sp_aamap, "fedusername", dir);
     372         [ +  - ]:        137 :     if (cf->idpatopt & 0x01)
     373                 :        137 :       zxid_add_mapped_attr(cf, ses, sp_meta, &at_stmt->gg, "mk_usr_a7n_to_sp", sp_aamap, "urn:oid:1.3.6.1.4.1.5923.1.1.1.6" /* eduPersonPrincipalName */, dir);
     374                 :            :     //zxid_mk_sa_attribute(cf, &at_stmt->gg, "urn:oid:1.3.6.1.4.1.5923.1.1.1.6" /* eduPersonPrincipalName */, "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", zx_dup_cstr(cf->ctx, dir));
     375                 :            :   }
     376                 :            : 
     377                 :            :   /* Following idpsesid attribute risks exposing federation-wide temporary unique ID.
     378                 :            :    * This is dangerous as it provides a correlation handle to participants of the
     379                 :            :    * session that would otherwise just have had pairwise pseudonyms. Even the regular
     380                 :            :    * session index is pariwise safe.
     381                 :            :    * As this is dangerous to privacy, it is disabled in the default AAMAP. You need to
     382                 :            :    * enable it explicitly in deployment specific AAMAP (in .all/.bs/.cf file) if you
     383                 :            :    * want it. There you can also specify whether it will be wrapped in assertion. */
     384   [ +  -  +  -  :        137 :   if (ses && ses->sid && *ses->sid)
                   +  - ]
     385                 :        137 :     zxid_add_mapped_attr(cf, ses, sp_meta, &at_stmt->gg, "mk_usr_a7n_to_sp", sp_aamap, "idpsesid", ses->sid);
     386                 :            : 
     387                 :        137 :   zxid_read_ldif_attrs(cf, ses, sp_meta, ".bs",       ses->uid, sp_aamap, at_stmt);
     388                 :        137 :   zxid_read_ldif_attrs(cf, ses, sp_meta, sp_name_buf, ses->uid, sp_aamap, at_stmt);
     389                 :        137 :   zxid_read_ldif_attrs(cf, ses, sp_meta, ".bs",       ".all",   sp_aamap, at_stmt);
     390                 :        137 :   zxid_read_ldif_attrs(cf, ses, sp_meta, sp_name_buf, ".all",   sp_aamap, at_stmt);
     391   [ +  +  -  + ]:        137 :   D("sp_eid(%s) bs_lvl=%d", sp_meta->eid, bs_lvl);
     392                 :            :   
     393                 :            :   /* Process bootstraps */
     394                 :            : 
     395                 :        137 :   name_from_path(dir, sizeof(dir), "%s" ZXID_UID_DIR "%s/.bs/", cf->path, ses->uid);
     396                 :        137 :   zxid_gen_boots(cf, ses, at_stmt, dir, bs_lvl);
     397                 :            :   
     398                 :        137 :   name_from_path(dir, sizeof(dir), "%s" ZXID_UID_DIR ".all/.bs/", cf->path);
     399                 :        137 :   zxid_gen_boots(cf, ses, at_stmt, dir, bs_lvl);
     400                 :            :   
     401                 :        137 :   D_DEDENT("mka7n: ");
     402                 :        137 :   return a7n;
     403                 :            : }
     404                 :            : 
     405                 :            : /*(i) Check federation, create federation if appropriate. */
     406                 :            : 
     407                 :            : /* Called by:  zxid_get_fed_nameid, zxid_imreq, zxid_nidmap_do */
     408                 :            : zxid_nid* zxid_check_fed(zxid_conf* cf, struct zx_str* affil, const char* uid, char allow_create, struct timeval* srcts, struct zx_str* issuer, struct zx_str* req_id, const char* sp_name_buf)
     409                 :       1225 : {
     410                 :            :   int got;
     411                 :            :   char buf[ZXID_MAX_USER];
     412                 :            :   char dir[ZXID_MAX_DIR];
     413                 :            :   zxid_nid* nameid;
     414                 :            :   struct zx_str* nid;
     415                 :            :   struct zx_attr_s* idp_eid;
     416                 :            : 
     417                 :       1225 :   got = read_all(sizeof(buf)-1, buf, "idpsso", 0, "%s" ZXID_UID_DIR "%s/%s/.mni" , cf->path, uid, sp_name_buf);
     418                 :            : 
     419         [ +  + ]:       1225 :   if (!got) {
     420         [ -  + ]:          1 :     if (allow_create == '1') {
     421                 :            : 
     422                 :          0 :       D_INDENT("allowcreate: ");
     423                 :            :       
     424                 :          0 :       name_from_path(dir, sizeof(dir), "%s" ZXID_UID_DIR "%s/%s", cf->path, uid, sp_name_buf);
     425   [ #  #  #  # ]:          0 :       if (MKDIR(dir, 0777) && errno != EEXIST) {
     426                 :          0 :         perror("mkdir for uid/sp fed");
     427                 :          0 :         ERR("Creating uid/sp federation directory(%s) failed", dir);
     428                 :          0 :         zxlog(cf, 0, srcts, 0, issuer, req_id, 0, 0, "N", "S", "EFILE", dir, "mkdir fail, permissions?");
     429                 :          0 :         D_DEDENT("allowcreate: ");
     430                 :          0 :         return 0;
     431                 :            :       }
     432                 :            :       
     433                 :          0 :       nid = zxid_mk_id(cf, "F", ZXID_ID_BITS);
     434                 :          0 :       nameid = zx_NEW_sa_NameID(cf->ctx,0);
     435                 :          0 :       nameid->Format = zx_ref_attr(cf->ctx, &nameid->gg, zx_Format_ATTR, SAML2_PERSISTENT_NID_FMT);
     436                 :          0 :       nameid->NameQualifier = idp_eid = zxid_my_ent_id_attr(cf,&nameid->gg,zx_NameQualifier_ATTR);
     437                 :          0 :       nameid->SPNameQualifier = zx_ref_len_attr(cf->ctx, &nameid->gg, zx_SPNameQualifier_ATTR, affil->len, affil->s);
     438                 :          0 :       zx_add_content(cf->ctx, &nameid->gg, nid);
     439                 :            : 
     440         [ #  # ]:          0 :       if (!write_all_path_fmt("put_fed", ZXID_MAX_USER, buf,
     441                 :            :                               "%s%s", dir, "/.mni",
     442                 :            :                               "%.*s|%.*s|%.*s|%.*s|",
     443                 :            :                               sizeof(SAML2_PERSISTENT_NID_FMT), SAML2_PERSISTENT_NID_FMT,
     444                 :            :                               idp_eid->g.len, idp_eid->g.s,
     445                 :            :                               affil->len, affil->s,
     446                 :            :                               nid->len, nid->s)) {
     447                 :          0 :         zxlog(cf, 0, srcts, 0, issuer, req_id, 0, nid, "N", "S", "EFILE", uid, "put_fed fail, permissions?");
     448                 :          0 :         D_DEDENT("allowcreate: ");
     449                 :          0 :         return 0;
     450                 :            :       }
     451                 :            : 
     452                 :            :       /* Create entry for reverse mapping from pseudonym nid to uid */
     453                 :            : 
     454                 :          0 :       name_from_path(dir, sizeof(dir), "%s" ZXID_NID_DIR "%s", cf->path, sp_name_buf);
     455   [ #  #  #  # ]:          0 :       if (MKDIR(dir, 0777) && errno != EEXIST) {
     456                 :          0 :         perror("mkdir for nid fed");
     457                 :          0 :         ERR("Creating nid index directory(%s) failed", dir);
     458                 :          0 :         zxlog(cf, 0, srcts, 0, issuer, req_id, 0, nid, "N", "S", "EFILE", dir, "mkdir fail, permissions?");
     459                 :          0 :         D_DEDENT("allowcreate: ");
     460                 :          0 :         return 0;
     461                 :            :       }
     462                 :            :       
     463                 :          0 :       name_from_path(dir, sizeof(dir), "%s" ZXID_NID_DIR "%s/%.*s", cf->path, sp_name_buf, nid->len, nid->s);
     464         [ #  # ]:          0 :       if (!write_all_path_fmt("put_nidmap", ZXID_MAX_USER, buf, "%s", dir, 0, "%s", uid)) {
     465                 :          0 :         zxlog(cf, 0, srcts, 0, issuer, req_id, 0, nid, "N", "S", "EFILE", uid, "put_nidmap fail, permissions?");
     466                 :          0 :         D_DEDENT("allowcreate: ");
     467                 :          0 :         return 0;
     468                 :            :       }
     469                 :            :       
     470                 :          0 :       zxlog(cf, 0, srcts, 0, issuer, req_id, 0, nid, "N", "K", "FEDNEW", uid, 0);
     471                 :          0 :       D_DEDENT("allowcreate: ");
     472                 :            : 
     473                 :            :     } else {
     474                 :          1 :       ERR("No federation for uid(%s) in affil(%.*s) and AllowCreate false %d", uid, affil->len, affil->s, allow_create);
     475                 :          1 :       return 0;
     476                 :            :     }
     477                 :            :   } else {
     478                 :       1224 :     buf[got] = 0;
     479                 :       1224 :     nameid = zxid_parse_mni(cf, buf, 0);
     480   [ +  -  +  -  :       1224 :     D("Old fed uid(%s) affil(%.*s) nid(%.*s)", uid, affil->len, affil->s, ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
          +  -  +  -  +  
          -  +  -  +  -  
                   -  + ]
     481                 :            :   }
     482                 :            : 
     483         [ -  + ]:       1224 :   if (!nameid) {
     484                 :          0 :     ERR("No federation for affil(%.*s) and AllowCreate false %d", affil->len, affil->s, allow_create);
     485                 :          0 :     return 0;
     486                 :            :   }
     487                 :       1224 :   return nameid;
     488                 :            : }
     489                 :            : 
     490                 :            : /*() Change NameID to be transient and record corresponding mapping. */
     491                 :            : 
     492                 :            : /* Called by:  zxid_get_fed_nameid x2, zxid_imreq x2, zxid_nidmap_do x2 */
     493                 :            : void zxid_mk_transient_nid(zxid_conf* cf, zxid_nid* nameid, const char* sp_name_buf, const char* uid)
     494                 :          1 : {
     495                 :            :   struct zx_str* nid;
     496                 :            :   char buf[ZXID_MAX_USER];
     497                 :            :   char dir[ZXID_MAX_DIR];
     498                 :            : 
     499                 :          1 :   D_INDENT("mk_trans: ");
     500                 :          1 :   nameid->Format = zx_ref_attr(cf->ctx, &nameid->gg, zx_Format_ATTR, SAML2_TRANSIENT_NID_FMT);
     501                 :          1 :   zx_add_content(cf->ctx, &nameid->gg, (nid = zxid_mk_id(cf, "T", ZXID_ID_BITS)));
     502                 :            :   
     503                 :            :   /* Create entry for reverse mapping from pseudonym nid to uid */
     504                 :            :   
     505                 :          1 :   name_from_path(dir, sizeof(dir), "%s" ZXID_NID_DIR "%s", cf->path, sp_name_buf);
     506   [ +  -  +  - ]:          1 :   if (MKDIR(dir, 0777) && errno != EEXIST) {
     507                 :          1 :     perror("mkdir for nid tmp");
     508                 :          1 :     ERR("Creating nid index directory(%s) failed", dir);
     509                 :          1 :     zxlog(cf, 0, 0, 0, 0, 0, 0, nid, "N", "S", "EFILE", dir, "mkdir fail, permissions?");
     510                 :          1 :     D_DEDENT("mk_trans: ");
     511                 :          1 :     return;
     512                 :            :   }
     513                 :            :   
     514                 :          0 :   name_from_path(dir, sizeof(dir), "%s" ZXID_NID_DIR "%s/%.*s", cf->path, sp_name_buf, nid->len, nid->s);
     515         [ #  # ]:          0 :   if (!write_all_path_fmt("put_nidmap_tmp", ZXID_MAX_USER, buf, "%s", dir, 0, "%s", uid)) {
     516                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, nid, "N", "S", "EFILE", uid, "put_nidmap fail, permissions?");
     517                 :          0 :     D_DEDENT("mk_trans: ");
     518                 :          0 :     return;
     519                 :            :   }
     520                 :            :   
     521                 :            :   /*zxlog(cf, 0, srcts, 0, issuer, req_id, 0, nid, "N", "K", "TMPNEW", uid, 0);*/
     522                 :          0 :   D_DEDENT("mk_trans: ");
     523                 :            : }
     524                 :            : 
     525                 :            : /*() Consider an EPR and user and generate the necessary access credential (SAML a7n).
     526                 :            :  * The EPR, which the caller obtained by parsing XML, is modified in place by adding
     527                 :            :  * the SecurityContext to the end of the kids list.
     528                 :            :  * Returns 1 on success, 0 on failure. */
     529                 :            : 
     530                 :            : /* Called by:  zxid_di_query, zxid_gen_boots x2 */
     531                 :            : int zxid_add_fed_tok2epr(zxid_conf* cf, zxid_ses* ses, zxid_epr* epr, int bs_lvl, char* logop)
     532                 :        282 : {
     533                 :        282 :   struct timeval srcts = {0,501000};
     534                 :            :   zxid_nid* nameid;
     535                 :            :   zxid_a7n* a7n;
     536                 :            :   zxid_entity* sp_meta;
     537                 :            :   struct zx_di_SecurityContext_s* sc;
     538                 :            :   struct zx_str* prvid;
     539                 :            :   struct zx_str* affil;
     540                 :            :   char sp_name_buf[ZXID_MAX_SP_NAME_BUF];
     541                 :            : 
     542   [ +  -  +  -  :        282 :   if (prvid = ZX_GET_CONTENT(epr->Metadata->ProviderID)) {
             +  -  +  - ]
     543                 :        282 :     sp_meta = zxid_get_ent_ss(cf, prvid);
     544         [ +  + ]:        282 :     if (!sp_meta) {
     545                 :        152 :       ERR("The metadata for provider could not be found or fetched. Reject. %d", 0);
     546                 :        152 :       return 0;
     547                 :            :     }
     548                 :            :   } else {
     549                 :          0 :     ERR("The EPR does not have ProviderID element. Reject. %d", 0);
     550                 :          0 :     return 0;
     551                 :            :   }
     552                 :            :   
     553                 :        130 :   affil = zxid_get_affil_and_sp_name_buf(cf, sp_meta, sp_name_buf);
     554   [ +  -  -  + ]:        260 :   D("sp_name_buf(%s) ProviderID(%.*s) di_allow_create=%d", sp_name_buf, prvid->len, prvid->s, cf->di_allow_create);
     555                 :            :   
     556                 :        130 :   nameid = zxid_get_fed_nameid(cf, prvid, affil, ses->uid, sp_name_buf, cf->di_allow_create,
     557                 :            :                                (cf->di_nid_fmt == 't'), &srcts, 0, logop);
     558                 :            :   
     559                 :            :   /* Generate access credential */
     560                 :            :   
     561                 :        130 :   a7n = zxid_mk_usr_a7n_to_sp(cf, ses, nameid, sp_meta, sp_name_buf, bs_lvl);
     562                 :            :   
     563         [ -  + ]:        130 :   if (!zxid_anoint_a7n(cf, cf->sso_sign & ZXID_SSO_SIGN_A7N, a7n, prvid, "DIA7N", ses->uid)) {
     564                 :          0 :     ERR("Failed to sign the assertion %d", 0);
     565                 :          0 :     return 0;
     566                 :            :   }
     567                 :            :   
     568         [ +  - ]:        130 :   if (!(sc = epr->Metadata->SecurityContext)) {
     569                 :        130 :     epr->Metadata->SecurityContext = sc = zx_NEW_di_SecurityContext(cf->ctx, 0);
     570                 :        130 :     zx_add_kid_before(&epr->Metadata->gg, ZX_TOK_NOT_FOUND, &sc->gg);
     571                 :            :   }
     572                 :            : 
     573         [ +  - ]:        130 :   if (!sc->SecurityMechID) {
     574                 :        130 :     sc->SecurityMechID = zx_dup_elem(cf->ctx, &sc->gg, zx_di_SecurityMechID_ELEM, WSF20_SEC_MECH_TLS_BEARER);
     575                 :            :   }
     576                 :            : 
     577         [ +  - ]:        130 :   if (!sc->Token)
     578                 :        130 :     sc->Token = zx_NEW_sec_Token(cf->ctx, &sc->gg);
     579                 :            :   
     580         [ +  - ]:        130 :   if (cf->di_a7n_enc) {
     581                 :        130 :     sc->Token->EncryptedAssertion = zxid_mk_enc_a7n(cf, &sc->Token->gg, a7n, sp_meta);
     582                 :            :   } else {
     583                 :          0 :     sc->Token->Assertion = a7n;
     584                 :          0 :     zx_add_kid(&sc->Token->gg, &a7n->gg);
     585                 :            :   }
     586                 :        130 :   zx_reverse_elem_lists(&sc->gg);
     587                 :        130 :   return 1;
     588                 :            : }
     589                 :            : 
     590                 :            : /*() Internal function, just to factor out some commonality between SSO and SSOS. */
     591                 :            : 
     592                 :            : /* Called by:  a7n_test, x509_test, zxid_idp_sso, zxid_ssos_anreq */
     593                 :            : zxid_a7n* zxid_sso_issue_a7n(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct timeval* srcts, zxid_entity* sp_meta, struct zx_str* acsurl, zxid_nid** nameid, char* logop, struct zx_sp_AuthnRequest_s* ar)
     594                 :          7 : {
     595                 :            :   zxid_a7n* a7n;
     596                 :            :   struct zx_sp_NameIDPolicy_s* nidpol;
     597                 :            :   struct zx_sa_SubjectConfirmation_s* sc;
     598                 :            :   struct zx_str* issuer;
     599                 :            :   struct zx_str* affil;
     600                 :            :   zxid_nid* tmpnameid;
     601                 :            :   char sp_name_buf[ZXID_MAX_SP_NAME_BUF];
     602   [ +  +  -  + ]:          7 :   D("sp_eid(%s)", sp_meta->eid);
     603         [ +  + ]:          7 :   if (!nameid)
     604                 :          1 :     nameid = &tmpnameid;
     605                 :            : 
     606   [ +  +  +  -  :          7 :   if (ar->IssueInstant && ar->IssueInstant->g.len && ar->IssueInstant->g.s)
                   +  - ]
     607                 :          6 :     srcts->tv_sec = zx_date_time_to_secs(ar->IssueInstant->g.s);
     608                 :            :   
     609                 :          7 :   nidpol = ar->NameIDPolicy;
     610   [ +  -  +  +  :          7 :   if (!cgi->allow_create && nidpol && nidpol->AllowCreate && nidpol->AllowCreate->g.s) {
             +  -  +  - ]
     611   [ +  -  -  + ]:          5 :     D("No allow_create from form, extract from SAMLRequest (%.*s) len=%d", nidpol->AllowCreate->g.len, nidpol->AllowCreate->g.s, nidpol->AllowCreate->g.len);
     612   [ +  -  +  -  :          5 :     cgi->allow_create = XML_TRUE_TEST(&nidpol->AllowCreate->g) ? '1':'0';
          -  +  #  #  #  
                      # ]
     613                 :            :   }
     614                 :            : 
     615   [ -  +  #  #  :          7 :   if ((!cgi->nid_fmt || !cgi->nid_fmt[0]) && nidpol && nidpol->Format && nidpol->Format->g.s) {
          +  +  +  -  +  
                      - ]
     616   [ +  -  -  + ]:          5 :     D("No Name ID Format from form, extract from SAMLRequest (%.*s) len=%d", nidpol->Format->g.len, nidpol->Format->g.s, nidpol->Format->g.len);
     617   [ -  +  #  # ]:          5 :     cgi->nid_fmt = nidpol->Format->g.len == sizeof(SAML2_TRANSIENT_NID_FMT)-1
     618                 :            :       && !memcmp(nidpol->Format->g.s, SAML2_TRANSIENT_NID_FMT, sizeof(SAML2_TRANSIENT_NID_FMT)-1)
     619                 :            :       ? "trnsnt" : "prstnt";
     620                 :            :   }
     621                 :            : 
     622                 :            :   /* Check for federation. */
     623                 :            :   
     624   [ +  -  +  -  :          7 :   issuer = ZX_GET_CONTENT(ar->Issuer);
                   +  - ]
     625   [ +  +  -  + ]:          7 :   affil = nidpol && nidpol->SPNameQualifier ? &nidpol->SPNameQualifier->g : issuer;
     626                 :          7 :   zxid_nice_sha1(cf, sp_name_buf, sizeof(sp_name_buf), affil, affil, 7);
     627   [ +  +  -  + ]:          7 :   D("sp_name_buf(%s)  allow_create=%d", sp_name_buf, cgi->allow_create);
     628                 :            : 
     629   [ +  +  -  + ]:          7 :   *nameid = zxid_get_fed_nameid(cf, issuer, affil, ses->uid, sp_name_buf, cgi->allow_create,
     630                 :            :                                 (cgi->nid_fmt && !strcmp(cgi->nid_fmt, "trnsnt")),
     631                 :            :                                 srcts, &ar->ID->g, logop);
     632         [ +  + ]:          7 :   if (logop) { logop[3]='S';  logop[4]='S';  logop[5]='O';  logop[6]=0;  /* Patch in SSO */ }
     633                 :            : 
     634                 :          7 :   a7n = zxid_mk_usr_a7n_to_sp(cf, ses, *nameid, sp_meta, sp_name_buf, 1);  /* SSO a7n */
     635                 :            : 
     636                 :            :   /* saml-profiles-2.0-os.pdf ll.549-551 requires SubjectConfirmation even though
     637                 :            :    * saml-core-2.0-os.pdf ll.653-657 says <SubjectConfirmation> [Zero or More]. The
     638                 :            :    * profile seems to make it mandatory. See profiles ll.554-560. */
     639                 :            : 
     640                 :          7 :   a7n->Subject->SubjectConfirmation = sc = zx_NEW_sa_SubjectConfirmation(cf->ctx, 0);
     641                 :          7 :   zx_add_kid_before(&a7n->Subject->gg, ZX_TOK_NOT_FOUND, &sc->gg);
     642                 :          7 :   sc->Method = zx_ref_attr(cf->ctx, &sc->gg, zx_Method_ATTR, SAML2_BEARER);
     643                 :          7 :   sc->SubjectConfirmationData = zx_NEW_sa_SubjectConfirmationData(cf->ctx, &sc->gg);
     644         [ +  + ]:          7 :   if (acsurl)
     645                 :          5 :     sc->SubjectConfirmationData->Recipient = zx_ref_len_attr(cf->ctx, &sc->SubjectConfirmationData->gg, zx_Recipient_ATTR, acsurl->len, acsurl->s);
     646                 :          7 :   sc->SubjectConfirmationData->NotOnOrAfter
     647                 :            :     = zx_ref_len_attr(cf->ctx, &sc->SubjectConfirmationData->gg, zx_NotOnOrAfter_ATTR, a7n->Conditions->NotOnOrAfter->g.len, a7n->Conditions->NotOnOrAfter->g.s);
     648                 :            : 
     649                 :          7 :   return a7n;
     650                 :            : }
     651                 :            : 
     652                 :            : /*(i) Generate SSO assertion and ship it to SP by chosen binding. User has already
     653                 :            :  * logged in by the time this is called. See also zxid_ssos_anreq() */
     654                 :            : 
     655                 :            : /* Called by:  zxid_idp_dispatch */
     656                 :            : struct zx_str* zxid_idp_sso(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_sp_AuthnRequest_s* ar)
     657                 :          5 : {
     658                 :            :   X509* sign_cert;
     659                 :            :   EVP_PKEY* sign_pkey;
     660                 :          5 :   int binding = 0;
     661                 :            :   struct zxsig_ref refs;
     662                 :            :   zxid_entity* sp_meta;
     663                 :          5 :   struct zx_str* acsurl = 0;
     664                 :            :   struct zx_str tmpss;
     665                 :            :   struct zx_str* ss;
     666                 :            :   struct zx_str* payload;
     667                 :          5 :   struct timeval srcts = {0,501000};
     668                 :            :   zxid_nid* nameid;
     669                 :            :   zxid_a7n* a7n;
     670                 :            :   struct zx_sp_Response_s* resp;
     671                 :            :   struct zx_e_Envelope_s* e;
     672                 :            :   char* p;
     673                 :            :   char logop[8];
     674                 :            : 
     675   [ +  -  +  -  :          5 :   if (!ar || !ZX_GET_CONTENT(ar->Issuer)) {
             +  -  -  + ]
     676                 :          0 :     ERR("No Issuer found in AuthnRequest %p", ar);
     677                 :          0 :     return zx_dup_str(cf->ctx, "* ERR");
     678                 :            :   }
     679                 :            : 
     680   [ +  -  +  -  :          5 :   sp_meta = zxid_get_ent_ss(cf, ZX_GET_CONTENT(ar->Issuer));
                   +  - ]
     681         [ -  + ]:          5 :   if (!sp_meta) {
     682                 :          0 :     ERR("The metadata for Issuer of the AuthnRequest could not be found or fetched %d", 0);
     683                 :          0 :     return zx_dup_str(cf->ctx, "* ERR");
     684                 :            :   }
     685   [ +  -  -  + ]:          5 :   D("sp_eid(%s)", sp_meta->eid);
     686                 :            : 
     687                 :            :   /* Figure out the binding and url */
     688                 :            : 
     689         [ -  + ]:          5 :   if (ar->AssertionConsumerServiceIndex) {
     690   [ #  #  #  # ]:          0 :     if (ar->ProtocolBinding || ar->AssertionConsumerServiceURL) {
     691                 :          0 :       ERR("When SP specifies AssertionConsumerServiceIndex in AuthnRequest, it SHOULD NOT specify ProtocolBinding(%p) or AssertionConsumerServiceURL(%p). They are ignored. AssertionConsumerServiceIndex approach is the preferred approach.", ar->ProtocolBinding, ar->AssertionConsumerServiceURL);
     692                 :            :     }
     693                 :          0 :     acsurl = zxid_sp_loc_by_index_raw(cf, cgi, sp_meta, ZXID_ACS_SVC, &ar->AssertionConsumerServiceIndex->g, &binding);
     694         [ -  + ]:          5 :   } else if (ar->ProtocolBinding) {
     695                 :          0 :     p = zx_str_to_c(cf->ctx, &ar->ProtocolBinding->g);
     696                 :          0 :     acsurl = zxid_sp_loc_raw(cf, cgi, sp_meta, ZXID_ACS_SVC, p, 0);
     697                 :          0 :     ZX_FREE(cf->ctx, p);
     698   [ #  #  #  # ]:          0 :     if (acsurl && ar->AssertionConsumerServiceURL) {
     699   [ #  #  #  # ]:          0 :       if (acsurl->len != ar->AssertionConsumerServiceURL->g.len
     700                 :            :           || memcmp(acsurl->s, ar->AssertionConsumerServiceURL->g.s, acsurl->len)) {
     701                 :          0 :         ERR("SECURITY/SPOOFING: SP specified in AuthnRequest an AssertionConsumerServiceURL(%.*s) but this does not agree with the metadata specified url(%.*s) for Binding(%.*s). SP would be better off using AssertionConsumerServiceIndex approach. The metadata is relied on and the AssertionConsumerServiceURL is ignored.", ar->AssertionConsumerServiceURL->g.len, ar->AssertionConsumerServiceURL->g.s, acsurl->len, acsurl->s, ar->ProtocolBinding->g.len, ar->ProtocolBinding->g.s);
     702                 :            :       }
     703                 :          0 :       binding = zxid_protocol_binding_map_saml2(&ar->ProtocolBinding->g);
     704                 :            :     }
     705                 :            :   }
     706         [ +  - ]:          5 :   if (!acsurl) {
     707   [ +  -  -  + ]:          5 :     D("AuthnRequest did not specify any ACS or binding. Using idp_pref_acs_binding(%s)", cf->idp_pref_acs_binding);
     708                 :          5 :     acsurl = zxid_sp_loc_raw(cf, cgi, sp_meta, ZXID_ACS_SVC, cf->idp_pref_acs_binding, 0);
     709         [ +  - ]:          5 :     if (acsurl) {
     710                 :          5 :       tmpss.len = strlen(cf->idp_pref_acs_binding);
     711                 :          5 :       tmpss.s = cf->idp_pref_acs_binding;
     712                 :          5 :       binding = zxid_protocol_binding_map_saml2(&tmpss);
     713                 :            :     } else {
     714   [ #  #  #  # ]:          0 :       D("Preferred binding not supported by SP metadata, using first ACS entry from metadata %d", 0);
     715   [ #  #  #  #  :          0 :       if (!sp_meta->ed || !sp_meta->ed->SPSSODescriptor || !sp_meta->ed->SPSSODescriptor->AssertionConsumerService || !sp_meta->ed->SPSSODescriptor->AssertionConsumerService->Location) {
             #  #  #  # ]
     716                 :          0 :         ERR("SP metadata does not contain any AssertionConsumerService. Can not complete SSO (SP metadata problem) %d", 0);
     717                 :          0 :         return zx_dup_str(cf->ctx, "* ERR");
     718                 :            :       }
     719                 :          0 :       acsurl = &sp_meta->ed->SPSSODescriptor->AssertionConsumerService->Location->g;
     720                 :          0 :       binding = zxid_protocol_binding_map_saml2(&sp_meta->ed->SPSSODescriptor->AssertionConsumerService->Binding->g);
     721                 :            :     }
     722                 :            :   }
     723                 :            : 
     724                 :            :   /* User ses->uid is already logged in, now check for federation with sp */
     725                 :            : 
     726                 :          5 :   a7n = zxid_sso_issue_a7n(cf, cgi, ses, &srcts, sp_meta, acsurl, &nameid, logop, ar);
     727                 :            :   
     728                 :            :   /* Sign, encrypt, and ship the assertion according to the binding. */
     729                 :            :   
     730   [ -  -  +  -  :          5 :   switch (binding) {
                      - ]
     731                 :            :   case 'e':
     732   [ #  #  #  # ]:          0 :     D("SAML2 PAOS ep(%.*s)", acsurl->len, acsurl->s);
     733                 :            :     
     734         [ #  # ]:          0 :     if (cf->sso_sign & ZXID_SSO_SIGN_A7N) {
     735                 :          0 :       ZERO(&refs, sizeof(refs));
     736                 :          0 :       refs.id = &a7n->ID->g;
     737                 :          0 :       refs.canon = zx_easy_enc_elem_sig(cf, &a7n->gg);
     738         [ #  # ]:          0 :       if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert paos")) {
     739                 :          0 :         a7n->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey);
     740                 :          0 :         zx_add_kid_after_sa_Issuer(&a7n->gg, &a7n->Signature->gg);
     741                 :            :       }
     742                 :            :     }
     743         [ #  # ]:          0 :     resp = zxid_mk_saml_resp(cf, a7n, cf->post_a7n_enc?sp_meta:0);
     744                 :          0 :     payload = zxid_anoint_sso_resp(cf, cf->sso_sign & ZXID_SSO_SIGN_RESP, resp, ar);
     745         [ #  # ]:          0 :     if (!payload)
     746                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     747                 :          0 :     zx_str_free(cf->ctx, payload);
     748                 :            : 
     749                 :            :     /* Generate SOAP envelope with ECP header */
     750                 :            : 
     751                 :          0 :     e = zx_NEW_e_Envelope(cf->ctx,0);
     752                 :            : 
     753                 :          0 :     e->Header = zx_NEW_e_Header(cf->ctx, &e->gg);
     754                 :          0 :     e->Header->ecp_Response = zx_NEW_ecp_Response(cf->ctx, &e->Header->gg);
     755                 :          0 :     e->Header->ecp_Response->mustUnderstand = zx_dup_attr(cf->ctx, &e->Header->ecp_Response->gg, zx_e_mustUnderstand_ATTR, "1");
     756                 :          0 :     e->Header->ecp_Response->actor = zx_ref_attr(cf->ctx, &e->Header->ecp_Response->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
     757                 :          0 :     e->Header->ecp_Response->AssertionConsumerServiceURL = zx_ref_len_attr(cf->ctx, &e->Header->ecp_Response->gg, zx_AssertionConsumerServiceURL_ATTR, acsurl->len, acsurl->s);
     758                 :            : 
     759                 :          0 :     e->Body = zx_NEW_e_Body(cf->ctx, &e->gg);
     760                 :          0 :     e->Body->Response = resp;
     761                 :            :     
     762                 :          0 :     ss = zx_easy_enc_elem_opt(cf, &e->gg);
     763                 :            : 
     764   [ #  #  #  #  :          0 :     zxlog(cf, 0, &srcts, 0, ZX_GET_CONTENT(ar->Issuer), 0, &a7n->ID->g, ZX_GET_CONTENT(nameid), "N", "K", logop, ses->uid, "PAOS2");
          #  #  #  #  #  
                #  #  # ]
     765                 :            : 
     766                 :            : 
     767                 :            :     /* *** Check what HTTP level headers PAOS needs */
     768   [ #  #  #  #  :          0 :     return zx_strf(cf->ctx, "Content-type: text/xml\r\nContent-Length: %d\r\n%s%s%s\r\n%.*s",
                   #  # ]
     769                 :            :                    ss->len,
     770                 :            :                    ses->setcookie?"Set-Cookie: ":"", ses->setcookie?ses->setcookie:"", ses->setcookie?"\r\n":"",
     771                 :            :                    ss->len, ss->s);
     772                 :            : 
     773                 :            :   case 'q':
     774   [ #  #  #  # ]:          0 :     D("SAML2 BRWS-POST-SIMPLE-SIGN ep(%.*s)", acsurl->len, acsurl->s);
     775                 :            : 
     776   [ #  #  #  #  :          0 :     if (!zxid_anoint_a7n(cf, cf->sso_sign & ZXID_SSO_SIGN_A7N_SIMPLE, a7n, ZX_GET_CONTENT(ar->Issuer), "SSOA7N", ses->uid))
             #  #  #  # ]
     777                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     778         [ #  # ]:          0 :     resp = zxid_mk_saml_resp(cf, a7n, cf->post_a7n_enc?sp_meta:0);
     779                 :          0 :     payload = zxid_anoint_sso_resp(cf, 0, resp, ar);
     780         [ #  # ]:          0 :     if (!payload)
     781                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     782                 :          0 :     ss = zxid_saml2_post_enc(cf, "SAMLResponse", payload, cgi->rs, 1, acsurl);
     783                 :          0 :     zx_str_free(cf->ctx, payload);
     784         [ #  # ]:          0 :     if (!ss)
     785                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     786                 :            : 
     787   [ #  #  #  #  :          0 :     zxlog(cf, 0, &srcts, 0, ZX_GET_CONTENT(ar->Issuer), 0, &a7n->ID->g, ZX_GET_CONTENT(nameid), "N", "K", logop, ses->uid, "SIMPSIG");
          #  #  #  #  #  
                #  #  # ]
     788                 :            : 
     789   [ #  #  #  #  :          0 :     return zx_strf(cf->ctx, "Content-type: text/html\r\nContent-Length: %d\r\n%s%s%s\r\n%.*s",
                   #  # ]
     790                 :            :                    ss->len,
     791                 :            :                    ses->setcookie?"Set-Cookie: ":"", ses->setcookie?ses->setcookie:"", ses->setcookie?"\r\n":"",
     792                 :            :                    ss->len, ss->s);
     793                 :            : 
     794                 :            :   case 'p':
     795   [ +  -  -  + ]:          5 :     D("SAML2 BRWS-POST ep(%.*s)", acsurl->len, acsurl->s);
     796                 :            : 
     797   [ +  -  +  -  :          5 :     if (!zxid_anoint_a7n(cf, cf->sso_sign & ZXID_SSO_SIGN_A7N, a7n, ZX_GET_CONTENT(ar->Issuer), "SSOA7N", ses->uid))
             +  -  -  + ]
     798                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     799         [ +  - ]:          5 :     resp = zxid_mk_saml_resp(cf, a7n, cf->post_a7n_enc?sp_meta:0);
     800                 :          5 :     payload = zxid_anoint_sso_resp(cf, cf->sso_sign & ZXID_SSO_SIGN_RESP, resp, ar);
     801         [ -  + ]:          5 :     if (!payload)
     802                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     803                 :            :     
     804                 :          5 :     ss = zxid_saml2_post_enc(cf, "SAMLResponse", payload, cgi->rs, 0, acsurl);
     805                 :          5 :     zx_str_free(cf->ctx, payload);
     806         [ -  + ]:          5 :     if (!ss)
     807                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     808                 :            :     
     809   [ +  -  +  -  :          5 :     zxlog(cf, 0, &srcts, 0, ZX_GET_CONTENT(ar->Issuer), 0, &a7n->ID->g, ZX_GET_CONTENT(nameid), "N", "K", logop, ses->uid, "BRWS-POST");
          +  -  +  -  +  
                -  +  - ]
     810                 :            :     
     811   [ -  +  -  +  :          5 :     return zx_strf(cf->ctx, "Content-type: text/html\r\nContent-Length: %d\r\n%s%s%s\r\n%.*s",
                   -  + ]
     812                 :            :                    ss->len,
     813                 :            :                    ses->setcookie?"Set-Cookie: ":"", ses->setcookie?ses->setcookie:"", ses->setcookie?"\r\n":"",
     814                 :            :                    ss->len, ss->s);
     815                 :            :     
     816                 :            :   case 'a':
     817   [ #  #  #  # ]:          0 :     D("SAML2 BRWS-ART ep(%.*s)", acsurl->len, acsurl->s);
     818                 :            : 
     819         [ #  # ]:          0 :     if (!cf->log_issue_a7n) {
     820                 :          0 :       INFO("LOG_ISSUE_A7N must be turned on in IdP configuration for artifact profile to work. Turning on now automatically. %d", 0);
     821                 :          0 :       cf->log_issue_a7n = 1;
     822                 :            :     }
     823   [ #  #  #  #  :          0 :     if (!zxid_anoint_a7n(cf, cf->sso_sign & ZXID_SSO_SIGN_A7N, a7n, ZX_GET_CONTENT(ar->Issuer), "SSOA7N", ses->uid))
             #  #  #  # ]
     824                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     825                 :          0 :     resp = zxid_mk_saml_resp(cf, a7n, 0);
     826                 :          0 :     payload = zxid_anoint_sso_resp(cf, cf->sso_sign & ZXID_SSO_SIGN_RESP, resp, ar);
     827         [ #  # ]:          0 :     if (!payload)
     828                 :          0 :       return zx_dup_str(cf->ctx, "* ERR");
     829                 :            :     
     830                 :            :     //ss = zxid_saml2_post_enc(cf, "SAMLResponse", pay_load, ar->RelayState);  *** redirect
     831                 :          0 :     zx_str_free(cf->ctx, payload);
     832                 :            :     /* *** Do artifact processing */
     833                 :            : 
     834   [ #  #  #  #  :          0 :     zxlog(cf, 0, &srcts, 0, ZX_GET_CONTENT(ar->Issuer), 0, &a7n->ID->g, ZX_GET_CONTENT(nameid), "N", "K", logop, ses->uid, "BRWS-ART");
          #  #  #  #  #  
                #  #  # ]
     835                 :            : 
     836                 :            : 
     837                 :            :   default:
     838   [ #  #  #  # ]:          0 :     NEVER("Unknown or unsupported binding %d", binding);
     839                 :            :   }
     840                 :            : 
     841                 :          0 :   return zx_dup_str(cf->ctx, "* ERR");
     842                 :            : }
     843                 :            : 
     844                 :            : /*() ID-WSF Authentication Service: check password and emit bootstrap(s)
     845                 :            :  * To generate the data, use:
     846                 :            :  *   perl -MMIME::Base64 -e 'print encode_base64("\0user\0pw\0")'
     847                 :            :  *   perl -MMIME::Base64 -e 'print encode_base64("\0tastest\0tas123\0")'
     848                 :            :  * See also: zxid_as_call_ses()
     849                 :            :  */
     850                 :            : 
     851                 :            : /* Called by:  zxid_sp_soap_dispatch */
     852                 :            : struct zx_as_SASLResponse_s* zxid_idp_as_do(zxid_conf* cf, struct zx_as_SASLRequest_s* req)
     853                 :         18 : {
     854                 :            :   zxid_cgi cgi;
     855                 :            :   zxid_ses sess;
     856                 :         18 :   struct zx_as_SASLResponse_s* res = zx_NEW_as_SASLResponse(cf->ctx,0);
     857                 :            :   struct zx_sa_AttributeStatement_s* at_stmt;
     858                 :            :   struct zx_sa_Attribute_s* at;
     859                 :            :   struct zx_sa_Attribute_s* at_next;
     860                 :            :   char* q;
     861                 :            :   char* u;
     862                 :            :   char* p;
     863                 :            :   char buf[1024];
     864                 :            :   char path[ZXID_MAX_BUF];
     865                 :            : 
     866                 :         18 :   ZERO(&cgi, sizeof(zxid_cgi));
     867                 :         18 :   ZERO(&sess, sizeof(zxid_ses));
     868                 :            : 
     869   [ +  -  +  -  :         18 :   if (SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(ZX_GET_CONTENT_LEN(req->Data)) >= sizeof(buf)-1) {
             +  -  -  + ]
     870   [ #  #  #  #  :          0 :     ERR("Too long username and password %p. limit=%d",ZX_GET_CONTENT(req->Data),sizeof(buf)-1);
                   #  # ]
     871                 :          0 :     res->Status = zxid_mk_lu_Status(cf, &res->gg, "ERR", 0, 0, 0);
     872                 :          0 :     return res;
     873                 :            :   }
     874   [ +  -  +  -  :         18 :   q = unbase64_raw(ZX_GET_CONTENT_S(req->Data), ZX_GET_CONTENT_S(req->Data) + ZX_GET_CONTENT_LEN(req->Data), buf, zx_std_index_64);
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     875                 :         18 :   *q = 0;
     876   [ -  +  #  # ]:         18 :   for (u = buf; *u && u < q; ++u) ;  /* skip initial */
     877   [ +  +  +  - ]:         18 :   for (p = ++u; *p && p < q; ++p) ;
     878                 :         18 :   ++p;
     879                 :         18 :   cgi.uid = u;
     880                 :         18 :   cgi.pw = p;
     881                 :            : 
     882         [ +  + ]:         18 :   if (zxid_pw_authn(cf, &cgi, &sess)) {
     883                 :         16 :     D_INDENT("as: ");
     884                 :         16 :     at_stmt = zx_NEW_sa_AttributeStatement(cf->ctx, 0 /* Do not attach */);
     885                 :         16 :     name_from_path(path, sizeof(path), "%s" ZXID_UID_DIR "%s/.bs/", cf->path, cgi.uid);
     886                 :         16 :     zxid_gen_boots(cf, &sess, at_stmt, path, 1);
     887                 :         16 :     name_from_path(path, sizeof(path), "%s" ZXID_UID_DIR ".all/.bs/", cf->path);
     888                 :         16 :     zxid_gen_boots(cf, &sess, at_stmt, path, 1);
     889                 :            : 
     890                 :            :     /* Kludgy extraction of the EPRs from the attributes. */
     891                 :            : 
     892                 :         16 :     at = at_stmt->Attribute;
     893         [ +  - ]:         16 :     if (at) {
     894                 :         16 :       res->EndpointReference = at->AttributeValue->EndpointReference;
     895   [ +  -  -  + ]:         16 :       D("TRANSMIT EPR to res %p %p", res->EndpointReference, res->EndpointReference->gg.g.n);
     896         [ +  + ]:         48 :       for (; at; at = at_next) {
     897         [ +  - ]:         32 :         if (at->AttributeValue->EndpointReference) {
     898   [ +  -  -  + ]:         32 :           D("TRANSMIT ANOTHER EPR to res %p %p", at->AttributeValue->EndpointReference, at->AttributeValue->EndpointReference->gg.g.n);
     899                 :         32 :           zx_add_kid(&res->gg, &at->AttributeValue->EndpointReference->gg);
     900                 :            :         } else {
     901   [ #  #  #  # ]:          0 :           D("NO EPR %p", at->AttributeValue->EndpointReference);
     902                 :            :         }
     903                 :         32 :         at_next = (struct zx_sa_Attribute_s*)at->gg.g.n;
     904                 :         32 :         ZX_FREE(cf->ctx, at);
     905                 :            :       }
     906                 :            :     }
     907                 :         16 :     ZX_FREE(cf->ctx, at_stmt);
     908                 :         16 :     res->Status = zxid_mk_lu_Status(cf, &res->gg, "OK", 0, 0, 0);
     909                 :            :     /*zx_reverse_elem_lists(&res->gg); already built right */
     910                 :         16 :     D_DEDENT("as: ");
     911                 :            :   } else {
     912                 :          2 :     ERR("Authentication failed uid(%s) pw(%s)", cgi.uid, cgi.pw);
     913                 :          2 :     res->Status = zxid_mk_lu_Status(cf, &res->gg, "ERR", 0, 0, 0);
     914                 :            :   }
     915                 :         18 :   return res;
     916                 :            : }
     917                 :            : 
     918                 :            : /* EOF  --  zxidpsso.c */

Generated by: LCOV version 1.9