1 /* zxumacall.c - UMA Client and Debugging Tool
2 * Copyright (c) 2014 Synergetics NV, All Rights Reserved.
3 * Author: Sampo Kellomaki (sampo@synergetics.be)
4 * This is confidential unpublished proprietary source code.
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: zxcot.c,v 1.5 2009-11-29 12:23:06 sampo Exp $
9 *
10 * 9.10.2014, created --Sampo
11 */
12
13 #include "platform.h" /* for dirent.h */
14
15 #include <string.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include "platform.h"
21 #include "errmac.h"
22 #include "zx.h"
23 #include "zxid.h"
24 #include "zxidutil.h"
25 #include "zxidconf.h"
26 #include "c/zxidvers.h"
27 #include "c/zx-const.h"
28 #include "c/zx-ns.h"
29 #include "c/zx-data.h"
30 #include "saml2.h"
31
32 char* help =
33 "zxumacall - UMA Client and Debugging tool R" ZXID_REL "\n\
34 UMA - User Managed Access and OAUTH2.0 are standards for access authorization of web services.\n\
35 Copyright (c) 2014 Synergetics NV, All Rights Reserved.\n\
36 Author: Sampo Kellomaki (sampo@synergetics.be)\n\
37 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
38 See http://www.apache.org/licenses/LICENSE-2.0\n\
39 Send well researched bug reports to the author. Home: zxid.org\n\
40 \n\
41 Usage: zxumacall [options] -s SESID -t SVCTYPE <req >resp\n\
42 zxumacall [options] -a IDP USER:PW -t SVCTYPE <req >resp\n\
43 zxumacall [options] -ua IDP UAT -t SVCTYPE <req >resp\n\
44 zxumacall [options] -a IDP USER:PW -t SVCTYPE -nd # Discovery only\n\
45 zxumacall [options] -a IDP USER:PW # Authentication only\n\
46 zxumacall [options] -dynclireg az_entity # Dynamic Client Registration\n\
47 zxumacall [options] -s SESID -im EID # Identity Mapping to EID\n\
48 zxumacall [options] -s SESID -l # List session cache\n\
49 -c CONF Optional configuration string (default -c CPATH=/var/zxid/)\n\
50 Most of the configuration is read from " ZXID_CONF_PATH "\n\
51 -s SESID Session ID referring to a directory in /var/zxid/ses\n\
52 Use zxidhlo to do SSO and then cut and paste from there.\n\
53 -a IDP USER:PW Use Authentication service to authenticate the user and\n\
54 create session. IDP is IdP's Entity ID. This is alternative to -s\n\
55 -t SVCTYPE Service Type URI. Used for discovery. Mandatory (omitting -t\n\
56 causes authorization only mode, provided that -az was specified).\n\
57 -dynclireg Invoke Dynamic Client Registration client to call Az Server's client registration endpoint\n\
58 -swstmt file (Optional) File containing signed Software Statement for dynreg\n\
59 -iat IAT (Optional) Initial Access Token for dynamic client registration\n\
60 -ua IDP UAT (Optional) Token for _uma_authn query string passed to OpenID-Connect server\n\
61 -client_id ID client_id (same as returned by dynamic client registration)\n\
62 -client_secret SS client_secret (same as returned by dynamic client registration)\n\
63 -rr NAME ICON_URI SCOPE TYPE Perform OAUTH2 Resource Set Registration\n\
64 -u EPURL Optional endpoint URL or ProviderID. Discovery must match this.\n\
65 -di DISCOOPTS Optional discovery options. Query string format.\n\
66 -din N Discovery index (default: 1=pick first).\n\
67 -az AZCREDS Optional authorization credentials. Query string format.\n\
68 N.B. For authorization to work PDP_URL configuration option is needed.\n\
69 -im DSTEID Map session's login identity to identity at some other SP using ID-WSF\n\
70 -nidmap DSTEID Map session's login identity to identity at some other SP using SAML\n\
71 -e ODY Pass request body as argument (default is to read from STDIN)\n\
72 -b In response, only return content of response body, omitting headers.\n\
73 -nd Discovery only (you need to specify -t SVCTYPE as well)\n\
74 -n Dryrun. Do not actually make call. Instead print it to stdout.\n\
75 -l List EPR cache (you need to specify -s SEDID or -a as well)\n\
76 -v Verbose messages.\n\
77 -q Be extra quiet.\n\
78 -d Turn on debugging.\n\
79 -dc Dump config.\n\
80 -h This help message\n\
81 -- End of options\n\
82 \n\
83 echo '<query>Foo</query>' | zxcall -a https://idp.tas3.eu/zxididp?o=B user:pw -t urn:x-demo-svc\n\
84 \n";
85
86 int dryrun = 0;
87 int verbose = 1;
88 int out_fmt = 0;
89 int din = 1;
90 int di_only = 0;
91 /* int ssos = 0; -nssos SSOS only (you need to specify -a IDP USER:PW as well)\n\ */
92 int listses = 0;
93 int dynclireg = 0;
94 extern char* iat; /* see zxidoauth.c */
95 extern char* _uma_authn; /* see zxidoauth.c */
96 char* swstmt = 0;
97 char* client_id;
98 char* client_secret;
99 char* rsrc_name = 0;
100 char* rsrc_icon_uri = 0;
101 char* rsrc_scope_url = 0;
102 char* rsrc_type = 0;
103 char* entid = 0;
104 char* idp = 0;
105 char* user = 0;
106 char* sid = 0;
107 char* svc = 0;
108 char* url = 0;
109 char* di = 0;
110 char* az = 0;
111 char* im_to = 0;
112 char* nidmap_to = 0;
113 char* bdy = 0;
114 zxid_conf* cf;
115
116 /* Called by: main x8, zxbusd_main, zxbuslist_main, zxbustailf_main, zxcall_main, zxcot_main, zxdecode_main */
opt(int * argc,char *** argv,char *** env)117 static void opt(int* argc, char*** argv, char*** env)
118 {
119 struct zx_str* ss;
120 if (*argc <= 1) return;
121
122 while (1) {
123 ++(*argv); --(*argc);
124
125 if (!(*argc) || ((*argv)[0][0] != '-')) break; /* normal exit from options loop */
126
127 switch ((*argv)[0][1]) {
128 case '-': if ((*argv)[0][2]) break;
129 ++(*argv); --(*argc);
130 DD("End of options by --");
131 return; /* -- ends the options */
132
133 case 'a':
134 switch ((*argv)[0][2]) {
135 case '\0':
136 ++(*argv); --(*argc);
137 if ((*argc) < 2) break;
138 idp = (*argv)[0];
139 ++(*argv); --(*argc);
140 user = (*argv)[0];
141 continue;
142 case 'z':
143 ++(*argv); --(*argc);
144 if ((*argc) < 1) break;
145 az = (*argv)[0];
146 continue;
147 }
148 break;
149
150 case 'b':
151 switch ((*argv)[0][2]) {
152 case '\0':
153 ++out_fmt;
154 continue;
155 }
156 break;
157
158 case 'c':
159 switch ((*argv)[0][2]) {
160 case '\0':
161 ++(*argv); --(*argc);
162 if ((*argc) < 1) break;
163 zxid_parse_conf(cf, (*argv)[0]);
164 continue;
165 case 'l':
166 if (!strcmp((*argv)[0],"-client_id")) {
167 ++(*argv); --(*argc);
168 if ((*argc) < 1) break;
169 client_id = (*argv)[0];
170 continue;
171 }
172 if (!strcmp((*argv)[0],"-client_secret")) {
173 ++(*argv); --(*argc);
174 if ((*argc) < 1) break;
175 client_secret = (*argv)[0];
176 continue;
177 }
178 break;
179 }
180 break;
181
182 case 'd':
183 switch ((*argv)[0][2]) {
184 case '\0':
185 ++errmac_debug;
186 if (errmac_debug == 2)
187 strncpy(errmac_instance, "\t\e[43mzxuma\e[0m", sizeof(errmac_instance));
188 continue;
189 case 'i':
190 switch ((*argv)[0][3]) {
191 case '\0':
192 ++(*argv); --(*argc);
193 if ((*argc) < 1) break;
194 di = (*argv)[0];
195 continue;
196 case 'n':
197 ++(*argv); --(*argc);
198 if ((*argc) < 1) break;
199 sscanf((*argv)[0], "%i", &din);
200 continue;
201 }
202 break;
203 case 'c':
204 ss = zxid_show_conf(cf);
205 if (verbose>1) {
206 printf("\n======== CONF ========\n%.*s\n^^^^^^^^ CONF ^^^^^^^^\n",ss->len,ss->s);
207 exit(0);
208 }
209 fprintf(stderr, "\n======== CONF ========\n%.*s\n^^^^^^^^ CONF ^^^^^^^^\n",ss->len,ss->s);
210 continue;
211 case 'y':
212 if (!strcmp((*argv)[0],"-dynclireg")) {
213 ++(*argv); --(*argc);
214 ++dynclireg;
215 continue;
216 }
217 break;
218 }
219 break;
220
221 case 'e':
222 switch ((*argv)[0][2]) {
223 case '\0':
224 ++(*argv); --(*argc);
225 if ((*argc) < 1) break;
226 bdy = (*argv)[0];
227 continue;
228 }
229 break;
230
231 case 'i':
232 switch ((*argv)[0][2]) {
233 case 'm':
234 ++(*argv); --(*argc);
235 if ((*argc) < 1) break;
236 im_to = (*argv)[0];
237 continue;
238 case 'a':
239 switch ((*argv)[0][3]) {
240 case 't':
241 ++(*argv); --(*argc);
242 if ((*argc) < 1) break;
243 iat = (*argv)[0];
244 continue;
245 }
246 break;
247 }
248 break;
249
250 case 'l':
251 switch ((*argv)[0][2]) {
252 case '\0':
253 ++listses;
254 continue;
255 #if 0
256 case 'i':
257 if (!strcmp((*argv)[0],"-license")) {
258 extern char* license;
259 fprintf(stderr, license);
260 exit(0);
261 }
262 break;
263 #endif
264 }
265 break;
266
267 case 'n':
268 switch ((*argv)[0][2]) {
269 case 'd':
270 ++di_only;
271 continue;
272 #if 0
273 case 's':
274 if (!strcmp((*argv)[0],"-nssos")) {
275 ++ssos;
276 continue;
277 }
278 break;
279 #endif
280 case 'i':
281 if (!strcmp((*argv)[0],"-nidmap")) {
282 ++(*argv); --(*argc);
283 if ((*argc) < 1) break;
284 nidmap_to = (*argv)[0];
285 continue;
286 }
287 break;
288 case '\0':
289 ++dryrun;
290 continue;
291 }
292 break;
293
294 case 'q':
295 switch ((*argv)[0][2]) {
296 case '\0':
297 verbose = 0;
298 continue;
299 }
300 break;
301
302 case 'r':
303 switch ((*argv)[0][2]) {
304 case 'r':
305 ++(*argv); --(*argc);
306 if ((*argc) < 4) break;
307 rsrc_name = (*argv)[0];
308 rsrc_icon_uri = (*argv)[1];
309 rsrc_scope_url = (*argv)[2];
310 rsrc_type = (*argv)[3];
311 ++(*argv); --(*argc);
312 ++(*argv); --(*argc);
313 ++(*argv); --(*argc);
314 continue;
315 }
316 break;
317
318 case 's':
319 switch ((*argv)[0][2]) {
320 case '\0':
321 ++(*argv); --(*argc);
322 if ((*argc) < 1) break;
323 sid = (*argv)[0];
324 continue;
325 }
326 break;
327
328 case 't':
329 switch ((*argv)[0][2]) {
330 case '\0':
331 ++(*argv); --(*argc);
332 if ((*argc) < 1) break;
333 svc = (*argv)[0];
334 continue;
335 }
336 break;
337
338 case 'u':
339 switch ((*argv)[0][2]) {
340 case '\0':
341 ++(*argv); --(*argc);
342 if ((*argc) < 1) break;
343 url = (*argv)[0];
344 continue;
345 case 'a':
346 ++(*argv); --(*argc);
347 if ((*argc) < 2) break;
348 idp = (*argv)[0];
349 _uma_authn = (*argv)[1];
350 ++(*argv); --(*argc);
351 continue;
352 }
353 break;
354
355 case 'v':
356 switch ((*argv)[0][2]) {
357 case '\0':
358 ++verbose;
359 continue;
360 }
361 break;
362
363 }
364 /* fall thru means unrecognized flag */
365 if (*argc)
366 fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
367 help:
368 if (verbose>1) {
369 printf("%s", help);
370 exit(0);
371 }
372 fprintf(stderr, "%s", help);
373 /*fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());*/
374 exit(3);
375 }
376 #if 0
377 if (!sid && !idp) {
378 fprintf(stderr, "MUST specify either -s or -a\n");
379 goto help;
380 }
381 #endif
382 }
383
384
385 /*() List session and especially its EPR cache to stdout.
386 * Typical name: /var/zxid/ses/SESID/SVCTYPE,SHA1
387 *
388 * cf:: ZXID configuration object, also used for memory allocation
389 * ses:: Session object in whose EPR cache the file is searched
390 *
391 * See also: zxid_find_epr() */
392
393 /* Called by: zxcall_main */
zxid_print_session(zxid_conf * cf,zxid_ses * ses)394 int zxid_print_session(zxid_conf* cf, zxid_ses* ses)
395 {
396 struct zx_root_s* r;
397 int epr_len, din = 0;
398 char path[ZXID_MAX_BUF];
399 char* epr_buf; /* MUST NOT come from stack. */
400 DIR* dir;
401 struct dirent * de;
402 zxid_epr* epr;
403 struct zx_a_Metadata_s* md;
404 struct zx_str* ss;
405
406 D_INDENT("lstses: ");
407
408 if (!name_from_path(path, sizeof(path), "%s" ZXID_SES_DIR "%s", cf->cpath, ses->sid)) {
409 D_DEDENT("lstses: ");
410 return 0;
411 }
412
413 printf("SESID: %s\nSESDIR: %s\n", ses->sid, path);
414 dir = opendir(path);
415 if (!dir) {
416 perror("opendir to find epr in session");
417 ERR("Opening session for find epr by opendir failed path(%s) sesptr=%p", path, ses);
418 D_DEDENT("lstses: ");
419 return 0;
420 }
421
422 while (de = readdir(dir)) {
423 D("%d Considering file(%s)", din, de->d_name);
424 if (de->d_name[0] == '.') /* . .. and "hidden" files */
425 continue;
426 if (de->d_name[strlen(de->d_name)-1] == '~') /* Ignore backups from hand edited EPRs. */
427 continue;
428 D("%d Checking EPR content file(%s)", din, de->d_name);
429 epr_buf = read_all_alloc(cf->ctx, "lstses", 1, &epr_len,
430 "%s" ZXID_SES_DIR "%s/%s", cf->cpath, ses->sid, de->d_name);
431 if (!epr_buf)
432 continue;
433
434 r = zx_dec_zx_root(cf->ctx, epr_len, epr_buf, "lstses");
435 if (!r || !r->EndpointReference) {
436 ERR("No EPR found. Failed to parse epr_buf(%.*s)", epr_len, epr_buf);
437 continue;
438 }
439 epr = r->EndpointReference;
440 ZX_FREE(cf->ctx, r);
441
442 md = epr->Metadata;
443 if (!md || !ZX_SIMPLE_ELEM_CHK(md->ServiceType)) {
444 ERR("No Metadata %p or ServiceType. Failed to parse epr_buf(%.*s)", md, epr_len, epr_buf);
445 printf("EPR %d no service type\n", ++din);
446 } else {
447 ss = ZX_GET_CONTENT(md->ServiceType);
448 printf("EPR %d SvcType: %.*s\n", ++din, ss->len, ss->s);
449 }
450 ss = zxid_get_epr_address(cf, epr);
451 printf(" URL: %.*s\n", ss?ss->len:0, ss?ss->s:"");
452 ss = zxid_get_epr_entid(cf, epr);
453 printf(" EntityID: %.*s\n", ss?ss->len:0, ss?ss->s:"");
454 ss = zxid_get_epr_desc(cf, epr);
455 printf(" Description: %.*s\n", ss?ss->len:0, ss?ss->s:"");
456 }
457 ZX_FREE(cf->ctx, epr_buf);
458 closedir(dir);
459 D_DEDENT("lstses: ");
460 return 0;
461 }
462
463 #if 0
464 char* zxid_scan_quoted(zxid_conf* cf, char* p, char** val, const char* res, comma_expected)
465 {
466 char quote;
467 char* p;
468 if (ONE_OF_2(*val, '"', '\'')) {
469 quote = *val;
470 ++val;
471 p = strchr(val, quote);
472 if (!p) {
473 ERR("Mismatched quote res(%s)", res);
474 return 0;
475 }
476 val = zx_dup_len_cstr(cf->ctx, val, p-val);
477 ++p;
478 if (comma_expected) {
479 if (*p != ',') {
480 ERR("Comma expected res(%s)", res);
481 return 0;
482 }
483 }
484 ++p;
485 } else {
486 p = strchr(val, ',');
487 if (comma_expected) {
488 if (!p) {
489 ERR("Comma expected res(%s)", res);
490 return 0;
491 }
492 } else {
493
494 }
495 val = zx_dup_len_cstr(cf->ctx, val, p-val);
496 ++p;
497 }
498 return val;
499
500 // *** buggy
501 }
502 #endif
503
504 /*(i) Make a HTTP POST call given payload string.
505 * The call is protected by UMA.
506 *
507 * cf:: ZXID configuration object, see zxid_new_conf()
508 * ses:: Session object that contains the EPR cache
509 * svctype:: URI (often the namespace URI) specifying the kind of service we
510 * wish to call. Used for EPR lookup or discovery.
511 * url:: (Optional) If provided, this argument has to match either
512 * the ProviderID, EntityID, or actual service endpoint URL.
513 * di_opt:: (Optional) Additional discovery options for selecting the
514 * service, query string format
515 * az_cred:: (Optional) Additional authorization credentials or
516 * attributes, query string format. These credentials will be populated
517 * to the attribute pool in addition to the ones obtained from SSO and
518 * other sources. Then a PDP is called to get an authorization decision
519 * (as well as obligations we pledge to support). See also PEPMAP
520 * configuration option. This implementes generalized (application
521 * independent) Requestor Out and Requestor In PEPs. To implement
522 * application dependent PEP features you should call zxid_az() directly.
523 * req:: request payload as string
524 * return:: SOAP Envelope of the response, as a string. You can parse this
525 * string to obtain all returned SOAP headers as well as the Body and its
526 * content. NULL on failure. ses->curflt and/or ses->curstatus contain
527 * more detailed error information. */
528
529 /* Called by: zxcall_main, zxid_callf */
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)530 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)
531 {
532 long rc;
533 struct zx_str* res;
534 char* p;
535 char* realm;
536 char* host_id;
537 char* as_uri;
538 char* error;
539 char* ticket = 0;
540 char* azhdr = 0;
541 /* *** try
542 GET /umaprotected/resource HTTP/1.1
543
544 HTTP/1.1 401 Unauthorized
545 WWW-Authenticate: UMA realm="example",
546 host_id="photoz.example.com",
547 as_uri="https://as.example.com"
548
549 *** obtain RPT by calling AS with AAT
550
551 GET /umaprotected/resource HTTP/1.1
552 Authorization: Bearer RPT
553
554 (see ResourceServer registers the desired permissions)
555
556 HTTP/1.1 403 Forbidden
557 WWW-Authenticate: UMA realm="example",
558 host_id="photoz.example.com",
559 as_uri="https://as.example.com",
560 error="insufficient_scope"
561
562 {
563 "ticket": "016f84e8-f9b9-11e0-bd6f-0021cc6004de"
564 }
565
566 OR
567
568 HTTP/1.1 200 OK
569
570 *** ResourceServer registers the desired permissions
571
572 POST /host/scope_reg_uri/photoz.example.com HTTP/1.1
573 Content-Type: application/json
574 Host: as.example.com
575
576 {
577 "resource_set_id": "112210f47de98100",
578 "scopes": [
579 "http://photoz.example.com/dev/actions/view",
580 "http://photoz.example.com/dev/actions/all"
581 ]
582 }
583
584 HTTP/1.1 201 Created
585 Content-Type: application/json
586 Location: https://as.example.com/permreg/host/photoz.example.com/5454345rdsaa4543
587 ...
588
589 {
590 "ticket": "016f84e8-f9b9-11e0-bd6f-0021cc6004de"
591 }
592
593 *** With ticket, enhance the RPT
594
595 */
596
597 while (1) {
598 curl_easy_setopt(cf->curl, CURLOPT_HEADER, 1);
599 res = zxid_http_cli(cf, -1, url, -1, req, "application/json", azhdr, 0x01);
600 if (!res) {
601 ERR("Call to url(%s) failed", url);
602 return 0;
603 }
604 curl_easy_getinfo(cf->curl, CURLINFO_RESPONSE_CODE, &rc);
605 switch (rc) {
606 case 200:
607 p = strstr(res->s, CRLF CRLF); /* find where headers end */
608 if (!p) {
609 ERR("Failed to find empty line separating headers from the body(%s)", res->s);
610 return res;
611 }
612 p = zx_dup_cstr(cf->ctx, p + sizeof(CRLF CRLF)-1);
613 ZX_FREE(cf->ctx, res->s);
614 res->s = p;
615 return res;
616 case 401:
617 #if 0
618 p = strstr(res->s, "WWW-Authenticate: UMA realm=");
619 if (!p) {
620 ERR("Failed to find WWW-Authenticate header or it is not of uma type res(%s)", res->s);
621 return res;
622 }
623 p = p + sizeof("WWW-Authenticate: UMA realm=")+1;
624 p = zxid_scan_quoted(cf, p, &realm);
625
626 p = strstr(p, "host_id=");
627 p = p + sizeof("host_id=")+1;
628 p = zxid_scan_quoted(cf, p, &host_id);
629 #else
630 if (sscanf(res->s, "WWW-Authenticate: UMA realm=\"%m[^\"]\" , host_id=\"%m[^\"]\", as_uri=\"%m[^\"]\"",
631 &realm, &host_id, &as_uri) != 3) {
632 ERR("Failed to find WWW-Authenticate header or it is not correctly formatted for UMA. res(%s)", res->s);
633 return res;
634 }
635 #endif
636
637 // Call AS to get RPT
638 zxid_oauth_call_rpt_endpoint(cf, ses, host_id, as_uri);
639 azhdr = zx_alloc_sprintf(cf->ctx, 0, "Authorization: Bearer %s", ses->rpt);
640 break;
641
642 case 403:
643 if (sscanf(res->s, "WWW-Authenticate: UMA realm=\"%m[^\"]\" , host_id=\"%m[^\"]\", as_uri=\"%m[^\"]\", error=\"%m[^\"]\"",
644 &realm, &host_id, &as_uri, &error) != 4) {
645 ERR("Failed to find WWW-Authenticate header or it is not correctly formatted for UMA. res(%s)", res->s);
646 return res;
647 }
648 if (strcmp(error, "insufficient_scope")) {
649 ERR("Expected error insufficient_scope, got(%s)", error);
650 return res;
651 }
652 p = strstr(res->s, CRLF CRLF); /* find where headers end */
653 if (!p) {
654 ERR("Failed to find empty line separating headers from the body(%s)", res->s);
655 return res;
656 }
657 ticket = zx_json_extract_dup(cf->ctx, res->s, "\"ticket\"");
658
659 // Call AS to get more perms
660 zxid_oauth_call_az_endpoint(cf, ses, host_id, as_uri, ticket);
661 azhdr = zx_alloc_sprintf(cf->ctx, 0, "Authorization: Bearer %s", ses->rpt);
662 break;
663
664 default:
665 ERR("Unexpected HTTP response %ld", rc);
666 return 0;
667 }
668 }
669 }
670
671 #ifndef zxumacall_main
672 #define zxumacall_main main
673 #endif
674
675 /*() Web Services Client tool */
676
677 /* Called by: */
zxumacall_main(int argc,char ** argv,char ** env)678 int zxumacall_main(int argc, char** argv, char** env)
679 {
680 int siz, got, n;
681 char* p;
682 struct zx_str* ss;
683 zxid_ses* ses = 0;
684 zxid_entity* idp_meta;
685 zxid_epr* epr;
686
687 strncpy(errmac_instance, CC_CYNY("\tzxuma"), sizeof(errmac_instance));
688 cf = zxid_new_conf_to_cf(0);
689 opt(&argc, &argv, &env);
690
691 if (dynclireg) {
692 ses = zxid_alloc_ses(cf);
693 ss = zxid_oauth_dynclireg_client(cf, 0, ses, url);
694 printf("%*s", ss->len, ss->s);
695 return 0;
696 }
697
698 if (sid) {
699 D("Existing session sesid(%s)", sid);
700 ses = zxid_fetch_ses(cf, sid);
701 if (!ses) {
702 ERR("Session not found or error in session sesid(%s)", sid);
703 return 1;
704 }
705 } else {
706 D("Obtain session from authentication service(%s)", idp);
707 idp_meta = zxid_get_ent(cf, idp);
708 if (!idp_meta) {
709 ERR("IdP metadata not found and could not be fetched. idp(%s)", idp);
710 return 1;
711 }
712 if (user) {
713 for (p = user; !ONE_OF_2(*p, ':', 0); ++p) ;
714 if (*p)
715 *p++ = 0;
716 ses = zxid_as_call(cf, idp_meta, user, p);
717 } else if (_uma_authn) {
718 ses = zxid_alloc_ses(cf);
719 zxid_oidc_as_call(cf, ses, idp_meta, _uma_authn);
720 }
721 if (!ses) {
722 ERR("Login using Authentication Service failed idp(%s)", idp);
723 return 1;
724 }
725 INFO("Logged in. Session in %s" ZXID_SES_DIR "%s\n%s", cf->cpath, STRNULLCHKD(ses->sid),STRNULLCHKD(ses->access_token));
726 }
727
728 if (rsrc_name) {
729 if (!ses->client_secret) {
730 if (!ses)
731 ses = zxid_alloc_ses(cf);
732 if (client_id) {
733 ses->client_id = client_id;
734 ses->client_secret = client_secret;
735 } else
736 zxid_oauth_dynclireg_client(cf, 0, ses, url);
737 }
738 zxid_oauth_rsrcreg_client(cf, 0, ses, url, rsrc_name, rsrc_icon_uri, rsrc_scope_url, rsrc_type);
739 return 0;
740 }
741
742 if (listses)
743 return zxid_print_session(cf, ses);
744
745 if (im_to) {
746 D("ID-WSF Map to identity at eid(%s)", im_to);
747 zxid_map_identity_token(cf, ses, im_to, 0);
748 //printf("%.*s\n", ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
749 return 0;
750 }
751
752 if (nidmap_to) {
753 D("SAML Map to identity at eid(%s)", nidmap_to);
754 zxid_nidmap_identity_token(cf, ses, nidmap_to, 0);
755 //printf("%.*s\n", ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
756 return 0;
757 }
758
759 if (di_only) {
760 D("Discover only. svctype(%s), dindex=%d", STRNULLCHK(svc), din);
761 epr = zxid_get_epr(cf, ses, svc, url, di, 0 /*action*/, din);
762 if (!epr) {
763 ERR("Discovery failed to find any epr of service type(%s)", STRNULLCHK(svc));
764 return 3;
765 }
766 for (din = 1; ;++din) {
767 epr = zxid_get_epr(cf, ses, svc, url, di, 0 /*action*/, din);
768 if (!epr)
769 break;
770 printf("%d. Found epr for service type(%s)\n", din, STRNULLCHK(svc));
771 ss = zxid_get_epr_desc(cf, epr);
772 printf(" Description: %.*s\n", ss?ss->len:0, ss?ss->s:"");
773 ss = zxid_get_epr_address(cf, epr);
774 printf(" EPURL: %.*s\n", ss?ss->len:0, ss?ss->s:"");
775 ss = zxid_get_epr_entid(cf, epr);
776 printf(" EntityID: %.*s\n", ss?ss->len:0, ss?ss->s:"");
777 }
778 return 0;
779 }
780
781 if (svc) {
782 D("Call service svctype(%s)", svc);
783 if (!bdy) {
784 if (verbose)
785 fprintf(stderr, "Reading request body from stdin...\n");
786 siz = 4096;
787 p = bdy = ZX_ALLOC(cf->ctx, siz);
788 while (1) {
789 n = read_all_fd(fdstdin, p, siz+bdy-p-1, &got);
790 if (n == -1) {
791 perror("reading SOAP req from stdin");
792 break;
793 }
794 p += got;
795 if (got < siz+bdy-p-1) break;
796 siz += 60*1024;
797 REALLOCN(bdy, siz);
798 }
799 *p = 0;
800 }
801 if (dryrun) {
802 if (verbose)
803 fprintf(stderr, "Dryrun. Call aborted.\n");
804 return 0;
805 }
806 if (verbose)
807 fprintf(stderr, "Calling...\n");
808
809 #if 1
810 ss = zxid_uma_call(cf, ses, svc, url, di, az, bdy);
811 printf("%.*s", ss->len, ss->s);
812 #else
813 ss = zxid_call(cf, ses, svc, url, di, az, bdy);
814 if (!ss || !ss->s) {
815 ERR("Call failed %p", ss);
816 return 2;
817 }
818 if (verbose)
819 fprintf(stderr, "Done. Call returned %d bytes.\n", ss->len);
820 if (out_fmt) {
821 p = zxid_extract_body(cf, ss->s);
822 printf("%s", p);
823 } else
824 printf("%.*s", ss->len, ss->s);
825 #endif
826 } else if (az) {
827 D("Call Az(%s)", az);
828 if (dryrun) {
829 if (verbose)
830 fprintf(stderr, "Dryrun. zxid_az() aborted.\n");
831 return 0;
832 }
833 if (zxid_az_cf_ses(cf, az, ses)) {
834 if (verbose)
835 fprintf(stderr, "Permit.\n");
836 return 0;
837 } else {
838 if (verbose)
839 fprintf(stderr, "Deny.\n");
840 return 1;
841 }
842 } else {
843 D("Neither service type (-t) nor -az supplied. Performed only authentication. %d",0);
844 if (verbose)
845 fprintf(stderr, "Authentication only.\n");
846 }
847 return 0;
848 }
849
850 /* EOF -- zxcall.c */
851