char* zxid_bn2b64(zxid_conf* cf, BIGNUM* bn) { char* bin; char* b64; char* e; int len; if (!bn) return zx_dup_cstr(cf->ctx, ""); bin = ZX_ALLOC(cf->ctx, BN_num_bytes(bn)); len = BN_bn2bin(bn, (unsigned char*)bin); b64 = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_LEN(len)+1); e = base64_fancy_raw(bin, len, b64, safe_basis_64, 1000000, 0, "", '='); *e = 0; ZX_FREE(cf->ctx, bin); return b64; }
/* Called by: */ int zxid_parse_psobj(zxid_conf* cf, struct zxid_psobj* obj, char* p, const char* lk) { char* name; char* val; char* q; struct zx_str* ss; struct zxid_perm* perm; for (; p; ++p) { name = p; p = strstr(p, ": "); if (!p) break; *p = 0; val = p+2; p = strchr(val, '\n'); /* *** parsing LDIF is fragile if values are multiline */ if (p) *p = 0; D("%s: ATTR(%s)=VAL(%s)", lk, name, val); switch (name[0]) { case 'd': if (!strcmp(name, "dn")) goto next; if (!strcmp(name, "dispname")) { obj->dispname = zx_dup_str(cf->ctx, val); goto next; } break; case 'i': if (!strcmp(name, "idpnid")) { obj->idpnid = zx_dup_str(cf->ctx, val); goto next; } if (!strcmp(name, "invid")) { ss = zx_dup_str(cf->ctx, val); ss->n = obj->invids; obj->invids = ss; goto next; } break; case 'p': if (!strcmp(name, "psobj")) { obj->psobj = zx_dup_str(cf->ctx, val); goto next; } if (!strcmp(name, "psobjref")) { ERR("%s: *** Child objects not yet supported (%s: %s)", lk, name, val); /*obj->child = zx_dup_str(cf->ctx, val); *** */ goto next; } if (!strcmp(name, "perm")) { perm = ZX_ZALLOC(cf->ctx, struct zxid_perm); q = strchr(val, '$'); if (q) { perm->eid = zx_dup_len_str(cf->ctx, q-val, val); perm->qs = zx_dup_str(cf->ctx, q); } else perm->eid = zx_dup_str(cf->ctx, val); perm->n = obj->perms; obj->perms = perm; goto next; } break; case 't': if (!strcmp(name, "tag")) { ss = zx_dup_str(cf->ctx, val); ss->n = obj->tags; obj->tags = ss; goto next; } break; case 'u': if (!strcmp(name, "uid")) { obj->uid = zx_dup_cstr(cf->ctx, val); goto next; } break; } ERR("%s: Unknown name(%s) val(%s) in psobj LDIF file. Ignored.", lk, name, val); next: val[-2] = ':'; /* restore */ if (p) *p = '\n'; else break; }
/* Called by: zxcall_main, zxid_callf */ struct zx_str* zxid_uma_call(zxid_conf* cf, zxid_ses* ses, const char* svctype, const char* url, const char* di_opt, const char* az_cred, const char* req) { long rc; struct zx_str* res; char* p; char* realm; char* host_id; char* as_uri; char* error; char* ticket = 0; char* azhdr = 0; /* *** try GET /umaprotected/resource HTTP/1.1 HTTP/1.1 401 Unauthorized WWW-Authenticate: UMA realm="example", host_id="photoz.example.com", as_uri="https://as.example.com" *** obtain RPT by calling AS with AAT GET /umaprotected/resource HTTP/1.1 Authorization: Bearer RPT (see ResourceServer registers the desired permissions) HTTP/1.1 403 Forbidden WWW-Authenticate: UMA realm="example", host_id="photoz.example.com", as_uri="https://as.example.com", error="insufficient_scope" { "ticket": "016f84e8-f9b9-11e0-bd6f-0021cc6004de" } OR HTTP/1.1 200 OK *** ResourceServer registers the desired permissions POST /host/scope_reg_uri/photoz.example.com HTTP/1.1 Content-Type: application/json Host: as.example.com { "resource_set_id": "112210f47de98100", "scopes": [ "http://photoz.example.com/dev/actions/view", "http://photoz.example.com/dev/actions/all" ] } HTTP/1.1 201 Created Content-Type: application/json Location: https://as.example.com/permreg/host/photoz.example.com/5454345rdsaa4543 ... { "ticket": "016f84e8-f9b9-11e0-bd6f-0021cc6004de" } *** With ticket, enhance the RPT */ while (1) { curl_easy_setopt(cf->curl, CURLOPT_HEADER, 1); res = zxid_http_cli(cf, -1, url, -1, req, "application/json", azhdr, 0x01); if (!res) { ERR("Call to url(%s) failed", url); return 0; } curl_easy_getinfo(cf->curl, CURLINFO_RESPONSE_CODE, &rc); switch (rc) { case 200: p = strstr(res->s, CRLF CRLF); /* find where headers end */ if (!p) { ERR("Failed to find empty line separating headers from the body(%s)", res->s); return res; } p = zx_dup_cstr(cf->ctx, p + sizeof(CRLF CRLF)-1); ZX_FREE(cf->ctx, res->s); res->s = p; return res; case 401: #if 0 p = strstr(res->s, "WWW-Authenticate: UMA realm="); if (!p) { ERR("Failed to find WWW-Authenticate header or it is not of uma type res(%s)", res->s); return res; } p = p + sizeof("WWW-Authenticate: UMA realm=")+1; p = zxid_scan_quoted(cf, p, &realm); p = strstr(p, "host_id="); p = p + sizeof("host_id=")+1; p = zxid_scan_quoted(cf, p, &host_id); #else if (sscanf(res->s, "WWW-Authenticate: UMA realm=\"%m[^\"]\" , host_id=\"%m[^\"]\", as_uri=\"%m[^\"]\"", &realm, &host_id, &as_uri) != 3) { ERR("Failed to find WWW-Authenticate header or it is not correctly formatted for UMA. res(%s)", res->s); return res; } #endif // Call AS to get RPT zxid_oauth_call_rpt_endpoint(cf, ses, host_id, as_uri); azhdr = zx_alloc_sprintf(cf->ctx, 0, "Authorization: Bearer %s", ses->rpt); break; case 403: if (sscanf(res->s, "WWW-Authenticate: UMA realm=\"%m[^\"]\" , host_id=\"%m[^\"]\", as_uri=\"%m[^\"]\", error=\"%m[^\"]\"", &realm, &host_id, &as_uri, &error) != 4) { ERR("Failed to find WWW-Authenticate header or it is not correctly formatted for UMA. res(%s)", res->s); return res; } if (strcmp(error, "insufficient_scope")) { ERR("Expected error insufficient_scope, got(%s)", error); return res; } p = strstr(res->s, CRLF CRLF); /* find where headers end */ if (!p) { ERR("Failed to find empty line separating headers from the body(%s)", res->s); return res; } ticket = zx_json_extract_dup(cf->ctx, res->s, "\"ticket\""); // Call AS to get more perms zxid_oauth_call_az_endpoint(cf, ses, host_id, as_uri, ticket); azhdr = zx_alloc_sprintf(cf->ctx, 0, "Authorization: Bearer %s", ses->rpt); break; default: ERR("Unexpected HTTP response %ld", rc); return 0; } } }