172
171
if (*result == NULL) {
173
172
/* something went wrong */
174
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
175
"oidc_metadata_file_read_json: JSON parsing (%s) returned an error: %s",
176
path, json_error.text);
173
oidc_error(r, "JSON parsing (%s) returned an error: %s", path,
180
178
if (!json_is_object(*result)) {
181
179
/* oops, no JSON */
182
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
183
"oidc_metadata_file_read_json: parsed JSON from (%s) did not contain a JSON object",
180
oidc_error(r, "parsed JSON from (%s) did not contain a JSON object",
185
182
json_decref(*result);
189
/* log successful metadata retrieval */
190
ap_log_rerror(APLOG_MARK, OIDC_DEBUG, 0, r,
191
"oidc_metadata_file_read_json: JSON parsed from file \"%s\"", path);
190
* check if the specified entry in metadata is a valid URI
192
static apr_byte_t oidc_metadata_is_valid_uri(request_rec *r, const char *type,
193
const char *issuer, const json_t *json, const char *key,
194
apr_byte_t is_mandatory) {
197
json_t *entry = NULL;
199
entry = json_object_get(json, key);
204
"%s (%s) JSON metadata does not contain the mandatory \"%s\" entry",
207
return (!is_mandatory);
210
if (!json_is_string(entry)) {
212
"%s (%s) JSON metadata contains a \"%s\" entry, but it is not a string value",
217
if (apr_uri_parse(r->pool, json_string_value(entry), &uri) != APR_SUCCESS) {
219
"%s (%s) JSON metadata contains a \"%s\" entry, but it is not a valid URI",
268
301
if (i == json_array_size(response_modes_supported)) {
269
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
270
"oidc_metadata_provider_is_valid: could not find a supported response mode in provider metadata (%s) for entry \"response_modes_supported\"",
303
"could not find a supported response mode in provider metadata (%s) for entry \"response_modes_supported\"",
275
ap_log_rerror(APLOG_MARK, OIDC_DEBUG, 0, r,
276
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata did not contain a \"response_modes_supported\" array; assuming that \"fragment\" and \"query\" are supported",
280
/* get a handle to the authorization endpoint */
281
json_t *j_authorization_endpoint = json_object_get(j_provider,
282
"authorization_endpoint");
283
if ((j_authorization_endpoint == NULL)
284
|| (!json_is_string(j_authorization_endpoint))) {
285
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
286
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata did not contain an \"authorization_endpoint\" string",
291
/* get a handle to the token endpoint */
292
json_t *j_token_endpoint = json_object_get(j_provider, "token_endpoint");
293
if ((j_token_endpoint == NULL) || (!json_is_string(j_token_endpoint))) {
294
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
295
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata did not contain a \"token_endpoint\" string",
300
/* get a handle to the user_info endpoint */
301
json_t *j_userinfo_endpoint = json_object_get(j_provider,
302
"userinfo_endpoint");
303
if ((j_userinfo_endpoint != NULL)
304
&& (!json_is_string(j_userinfo_endpoint))) {
305
ap_log_rerror(APLOG_MARK, OIDC_DEBUG, 0, r,
306
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata contains a \"userinfo_endpoint\" entry, but it is not a string value",
309
// TODO: check for valid URL
311
/* get a handle to the jwks_uri */
312
json_t *j_jwks_uri = json_object_get(j_provider, "jwks_uri");
313
if ((j_jwks_uri == NULL) || (!json_is_string(j_jwks_uri))) {
314
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
315
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata did not contain a \"jwks_uri\" string",
309
"provider (%s) JSON metadata did not contain a \"response_modes_supported\" array; assuming that \"fragment\" and \"query\" are supported",
313
/* check the required authorization endpoint */
314
if (oidc_metadata_is_valid_uri(r, "provider", issuer, j_provider,
315
"authorization_endpoint", TRUE) == FALSE)
318
/* check the optional token endpoint */
319
if (oidc_metadata_is_valid_uri(r, "provider", issuer, j_provider,
320
"token_endpoint", FALSE) == FALSE)
323
/* check the optional user info endpoint */
324
if (oidc_metadata_is_valid_uri(r, "provider", issuer, j_provider,
325
"userinfo_endpoint", FALSE) == FALSE)
328
/* check the optional JWKs URI */
329
if (oidc_metadata_is_valid_uri(r, "provider", issuer, j_provider,
330
"jwks_uri", FALSE) == FALSE)
320
333
/* find out what type of authentication the token endpoint supports (we only support post or basic) */
321
334
json_t *j_token_endpoint_auth_methods_supported = json_object_get(
322
335
j_provider, "token_endpoint_auth_methods_supported");
323
336
if ((j_token_endpoint_auth_methods_supported == NULL)
324
337
|| (!json_is_array(j_token_endpoint_auth_methods_supported))) {
325
ap_log_rerror(APLOG_MARK, OIDC_DEBUG, 0, r,
326
"oidc_metadata_provider_is_valid: provider (%s) JSON metadata did not contain a \"token_endpoint_auth_methods_supported\" array, assuming \"client_secret_basic\" is supported",
339
"provider (%s) JSON metadata did not contain a \"token_endpoint_auth_methods_supported\" array, assuming \"client_secret_basic\" is supported",
539
549
apr_file_unlock(fd);
540
550
apr_file_close(fd);
542
ap_log_rerror(APLOG_MARK, OIDC_DEBUG, 0, r,
543
"oidc_metadata_file_write: file \"%s\" written; number of bytes (%" APR_SIZE_T_FMT ")",
552
oidc_debug(r, "file \"%s\" written; number of bytes (%" APR_SIZE_T_FMT ")",
549
/* callback function type for checking metadata validity (provider or client) */
550
typedef apr_byte_t (*oidc_is_valid_function_t)(request_rec *, json_t *,
554
* helper function to get the JSON (client or provider) metadata from the specified file path and check its validity
556
static apr_byte_t oidc_metadata_get_and_check(request_rec *r, const char *path,
557
const char *issuer, oidc_is_valid_function_t metadata_is_valid,
558
json_t **j_metadata, apr_byte_t remove_when_invalid) {
561
apr_status_t rc = APR_SUCCESS;
564
/* read the metadata from a file in to a variable */
565
if (oidc_metadata_file_read_json(r, path, j_metadata) == FALSE)
568
if (metadata_is_valid) {
569
/* we've got metadata that is JSON and no error-JSON, but now we check provider/client validity */
570
if (metadata_is_valid(r, *j_metadata, issuer) == FALSE)
574
/* all OK if we got here */
580
* this is expired or otherwise invalid metadata, we're probably going to get
581
* new metadata, so delete the file first, if it (still) exists at all
583
if ((remove_when_invalid == TRUE)
584
&& (apr_stat(&fi, path, APR_FINFO_MTIME, r->pool) == APR_SUCCESS)) {
586
if ((rc = apr_file_remove(path, r->pool)) != APR_SUCCESS) {
587
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
588
"oidc_metadata_get_and_check: could not delete invalid metadata file %s (%s)",
589
path, apr_strerror(rc, s_err, sizeof(s_err)));
591
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
592
"oidc_metadata_get_and_check: removed invalid metadata file %s",
601
* helper function to retrieve provider metadata from a URL, check it and store it
603
static apr_byte_t oidc_metadata_provider_retrieve_and_store(request_rec *r,
604
oidc_cfg *cfg, const char *url, const char *issuer, const char *path,
605
json_t **j_metadata) {
606
const char *response = NULL;
608
/* no valid provider metadata, get it at the specified URL with the specified parameters */
609
if (oidc_util_http_get(r, url, NULL, NULL, NULL,
610
cfg->provider.ssl_validate_server, &response,
611
cfg->http_timeout_short, cfg->outgoing_proxy) == FALSE)
614
/* decode and see if it is not an error response somehow */
615
if (oidc_util_decode_json_and_check_error(r, response, j_metadata) == FALSE)
618
/* check to see if it is valid metadata */
619
if (oidc_metadata_provider_is_valid(r, *j_metadata, issuer) == FALSE)
622
/* since it is valid, write the obtained provider metadata file */
623
if (oidc_metadata_file_write(r, path, response) == FALSE)
631
* helper function to retrieve client metadata from a dynamic registration URL, check it and store it
633
static apr_byte_t oidc_metadata_client_retrieve_and_store(request_rec *r,
634
oidc_cfg *cfg, const char *url, json_t *data, const char *issuer,
635
const char *path, json_t **j_metadata, int ssl_validate_server,
636
const char *bearer_token) {
637
const char *response = NULL;
638
apr_byte_t rc = FALSE;
642
"idp/client-registration.openid") != NULL) {
644
apr_table_t *params = apr_table_make(r->pool, 3);
645
json_t *v = json_object_get(data, "client_name");
646
apr_table_addn(params, "client_name", json_string_value(v));
647
apr_table_addn(params, "operation", "client_register");
648
apr_table_addn(params, "redirect_uris", cfg->redirect_uri);
649
rc = oidc_util_http_get(r, url, params, NULL, bearer_token,
650
ssl_validate_server, &response, cfg->http_timeout_short,
651
cfg->outgoing_proxy);
656
/* no valid provider metadata, get it at the specified URL with the specified parameters */
657
rc = oidc_util_http_post_json(r, url, data, NULL, bearer_token,
658
ssl_validate_server, &response, cfg->http_timeout_short,
659
cfg->outgoing_proxy);
559
* register the client with the OP using Dynamic Client Registration
561
static apr_byte_t oidc_metadata_client_register(request_rec *r, oidc_cfg *cfg,
562
oidc_provider_t *provider, json_t **j_client, const char **response) {
564
/* assemble the JSON registration request */
565
json_t *data = json_object();
566
json_object_set_new(data, "client_name",
567
json_string(provider->client_name));
568
json_object_set_new(data, "redirect_uris",
569
json_pack("[s]", cfg->redirect_uri));
571
json_t *response_types = json_array();
572
apr_array_header_t *flows = oidc_proto_supported_flows(r->pool);
574
for (i = 0; i < flows->nelts; i++) {
575
json_array_append_new(response_types,
576
json_string(((const char**) flows->elts)[i]));
578
json_object_set_new(data, "response_types", response_types);
580
if (provider->client_contact != NULL) {
581
json_object_set_new(data, "contacts",
582
json_pack("[s]", provider->client_contact));
585
if (provider->client_jwks_uri) {
586
json_object_set_new(data, "jwks_uri",
587
json_string(provider->client_jwks_uri));
588
} else if (cfg->public_keys != NULL) {
589
json_object_set_new(data, "jwks_uri",
591
apr_psprintf(r->pool, "%s?jwks=rsa",
592
cfg->redirect_uri)));
595
if (provider->id_token_signed_response_alg != NULL) {
596
json_object_set_new(data, "id_token_signed_response_alg",
597
json_string(provider->id_token_signed_response_alg));
599
if (provider->id_token_encrypted_response_alg != NULL) {
600
json_object_set_new(data, "id_token_encrypted_response_alg",
601
json_string(provider->id_token_encrypted_response_alg));
603
if (provider->id_token_encrypted_response_enc != NULL) {
604
json_object_set_new(data, "id_token_encrypted_response_enc",
605
json_string(provider->id_token_encrypted_response_enc));
608
if (provider->userinfo_signed_response_alg != NULL) {
609
json_object_set_new(data, "userinfo_signed_response_alg",
610
json_string(provider->userinfo_signed_response_alg));
612
if (provider->userinfo_encrypted_response_alg != NULL) {
613
json_object_set_new(data, "userinfo_encrypted_response_alg",
614
json_string(provider->userinfo_encrypted_response_alg));
616
if (provider->userinfo_encrypted_response_enc != NULL) {
617
json_object_set_new(data, "userinfo_encrypted_response_enc",
618
json_string(provider->userinfo_encrypted_response_enc));
621
json_object_set_new(data, "initiate_login_uri",
622
json_string(cfg->redirect_uri));
624
/* dynamically register the client with the specified parameters */
625
if (oidc_util_http_post_json(r, provider->registration_endpoint_url, data,
626
NULL, provider->registration_token, provider->ssl_validate_server, response,
627
cfg->http_timeout_short, cfg->outgoing_proxy) == FALSE) {
661
631
json_decref(data);
665
633
/* decode and see if it is not an error response somehow */
666
if (oidc_util_decode_json_and_check_error(r, response, j_metadata) == FALSE)
669
/* check to see if it is valid metadata */
670
if (oidc_metadata_client_is_valid(r, *j_metadata, issuer) == FALSE)
673
/* since it is valid, write the obtained provider metadata file */
674
if (oidc_metadata_file_write(r, path, response) == FALSE)
634
return oidc_util_decode_json_and_check_error(r, *response, j_client);
682
638
* helper function to get the JWKs for the specified issuer
684
static apr_byte_t oidc_metadata_jwks_retrieve_and_store(request_rec *r,
640
static apr_byte_t oidc_metadata_jwks_retrieve_and_cache(request_rec *r,
685
641
oidc_cfg *cfg, oidc_provider_t *provider, json_t **j_jwks) {
687
643
const char *response = NULL;
704
* use OpenID Connect Discovery to get metadata for the specified issuer
706
apr_byte_t oidc_metadata_provider_retrieve(request_rec *r, oidc_cfg *cfg,
707
const char *issuer, const char *url, json_t **j_metadata,
708
const char **response) {
710
/* get provider metadata from the specified URL with the specified parameters */
711
if (oidc_util_http_get(r, url, NULL, NULL, NULL,
712
cfg->provider.ssl_validate_server, response,
713
cfg->http_timeout_short, cfg->outgoing_proxy) == FALSE)
716
/* decode and see if it is not an error response somehow */
717
if (oidc_util_decode_json_and_check_error(r, *response, j_metadata) == FALSE)
720
/* check to see if it is valid metadata */
721
if (oidc_metadata_provider_is_valid(r, *j_metadata, issuer) == FALSE)
751
729
* see if we have provider metadata and check its validity
752
* if not, use OpenID Connect Provider Issuer Discovery to get it, check it and store it
730
* if not, use OpenID Connect Discovery to get it, check it and store it
754
732
static apr_byte_t oidc_metadata_provider_get(request_rec *r, oidc_cfg *cfg,
755
733
const char *issuer, json_t **j_provider) {
735
/* holds the response data/string/JSON from the OP */
736
const char *response = NULL;
757
738
/* get the full file path to the provider metadata for this issuer */
758
739
const char *provider_path = oidc_metadata_provider_file_path(r, issuer);
760
741
/* see if we have valid metadata already, if so, return it */
761
if (oidc_metadata_get_and_check(r, provider_path, issuer,
762
oidc_metadata_provider_is_valid, j_provider, FALSE) == TRUE)
742
if (oidc_metadata_file_read_json(r, provider_path, j_provider) == TRUE) {
744
/* return the validation result */
745
return oidc_metadata_provider_is_valid(r, *j_provider, issuer);
765
748
// TODO: how to do validity/expiry checks on provider metadata
803
798
static apr_byte_t oidc_metadata_client_get(request_rec *r, oidc_cfg *cfg,
804
799
const char *issuer, oidc_provider_t *provider, json_t **j_client) {
806
/* get the full file path to the provider metadata for this issuer */
801
/* get the full file path to the client metadata for this issuer */
807
802
const char *client_path = oidc_metadata_client_file_path(r, issuer);
809
/* see if we already have valid client metadata, if so, return TRUE */
810
if (oidc_metadata_get_and_check(r, client_path, issuer,
811
oidc_metadata_client_is_valid, j_client, TRUE) == TRUE)
804
/* see if we have valid metadata already, if so, return it */
805
if (oidc_metadata_file_read_json(r, client_path, j_client) == TRUE) {
807
/* if the client metadata is (still) valid, return it */
808
if (oidc_metadata_client_is_valid(r, *j_client, issuer) == TRUE)
814
812
/* at this point we have no valid client metadata, see if there's a registration endpoint for this provider */
815
813
if (provider->registration_endpoint_url == NULL) {
816
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
817
"oidc_metadata_client_get: no (valid) client metadata exists for provider (%s) and provider JSON object did not contain a (valid) \"registration_endpoint\" string",
815
"no (valid) client metadata exists for provider (%s) and provider JSON object did not contain a (valid) \"registration_endpoint\" string",
822
/* go and use Dynamic Client registration to fetch ourselves new client metadata */
823
json_t *data = json_object();
824
json_object_set_new(data, "client_name",
825
json_string(provider->client_name));
826
json_object_set_new(data, "redirect_uris",
827
json_pack("[s]", cfg->redirect_uri));
829
json_t *response_types = json_array();
830
apr_array_header_t *flows = oidc_proto_supported_flows(r->pool);
832
for (i = 0; i < flows->nelts; i++) {
833
json_array_append_new(response_types,
834
json_string(((const char**) flows->elts)[i]));
836
json_object_set_new(data, "response_types", response_types);
838
if (provider->client_contact != NULL) {
839
json_object_set_new(data, "contacts",
840
json_pack("[s]", provider->client_contact));
843
if (provider->client_jwks_uri) {
844
json_object_set_new(data, "jwks_uri",
845
json_string(provider->client_jwks_uri));
846
} else if (cfg->public_keys != NULL) {
847
json_object_set_new(data, "jwks_uri",
849
apr_psprintf(r->pool, "%s?jwks=rsa",
850
cfg->redirect_uri)));
853
if (provider->id_token_signed_response_alg != NULL) {
854
json_object_set_new(data, "id_token_signed_response_alg",
855
json_string(provider->id_token_signed_response_alg));
857
if (provider->id_token_encrypted_response_alg != NULL) {
858
json_object_set_new(data, "id_token_encrypted_response_alg",
859
json_string(provider->id_token_encrypted_response_alg));
861
if (provider->id_token_encrypted_response_enc != NULL) {
862
json_object_set_new(data, "id_token_encrypted_response_enc",
863
json_string(provider->id_token_encrypted_response_enc));
866
if (provider->userinfo_signed_response_alg != NULL) {
867
json_object_set_new(data, "userinfo_signed_response_alg",
868
json_string(provider->userinfo_signed_response_alg));
870
if (provider->userinfo_encrypted_response_alg != NULL) {
871
json_object_set_new(data, "userinfo_encrypted_response_alg",
872
json_string(provider->userinfo_encrypted_response_alg));
874
if (provider->userinfo_encrypted_response_enc != NULL) {
875
json_object_set_new(data, "userinfo_encrypted_response_enc",
876
json_string(provider->userinfo_encrypted_response_enc));
879
json_object_set_new(data, "initiate_login_uri",
880
json_string(cfg->redirect_uri));
882
/* try and get it from there, checking it and storing it if successful */
883
return oidc_metadata_client_retrieve_and_store(r, cfg,
884
provider->registration_endpoint_url, data, issuer, client_path,
885
j_client, provider->ssl_validate_server,
886
provider->registration_token);
820
/* try and get client metadata by registering the client at the registration endpoint */
821
const char *response = NULL;
822
if (oidc_metadata_client_register(r, cfg, provider, j_client,
826
/* check to see if it is valid metadata */
827
if (oidc_metadata_client_is_valid(r, *j_client, issuer) == FALSE)
830
/* since it is valid, write the obtained client metadata file */
831
if (oidc_metadata_file_write(r, client_path, response) == FALSE)
944
* find out what type of authentication we must provide to the token endpoint (we only support post or basic)
890
* parse the JSON provider metadata in to a oidc_provider_t struct but do not override values already set
946
static const char * oidc_metadata_token_endpoint_auth(request_rec *r,
947
json_t *j_client, json_t *j_provider) {
949
const char *result = "client_secret_basic";
951
/* see if one is defined in the client metadata */
952
json_t *token_endpoint_auth_method = json_object_get(j_client,
953
"token_endpoint_auth_method");
954
if (token_endpoint_auth_method != NULL) {
955
if (json_is_string(token_endpoint_auth_method)) {
956
if (strcmp(json_string_value(token_endpoint_auth_method),
957
"client_secret_post") == 0) {
958
result = "client_secret_post";
961
if (strcmp(json_string_value(token_endpoint_auth_method),
962
"client_secret_basic") == 0) {
963
result = "client_secret_basic";
966
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
967
"oidc_metadata_token_endpoint_auth: unsupported client auth method \"%s\" in client metadata for entry \"token_endpoint_auth_method\"",
968
json_string_value(token_endpoint_auth_method));
970
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
971
"oidc_metadata_token_endpoint_auth: unexpected JSON object type [%d] (!= APR_JSON_STRING) in client metadata for entry \"token_endpoint_auth_method\"",
972
token_endpoint_auth_method->type);
976
/* no supported value in the client metadata, find a supported one in the provider metadata */
977
json_t *j_token_endpoint_auth_methods_supported = json_object_get(
978
j_provider, "token_endpoint_auth_methods_supported");
980
if ((j_token_endpoint_auth_methods_supported != NULL)
981
&& (json_is_array(j_token_endpoint_auth_methods_supported))) {
984
i < json_array_size(j_token_endpoint_auth_methods_supported);
986
json_t *elem = json_array_get(
987
j_token_endpoint_auth_methods_supported, i);
988
if (!json_is_string(elem)) {
989
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
990
"oidc_metadata_token_endpoint_auth: unhandled in-array JSON object type [%d] in provider metadata for entry \"token_endpoint_auth_methods_supported\"",
994
if (strcmp(json_string_value(elem), "client_secret_post") == 0) {
995
result = "client_secret_post";
998
if (strcmp(json_string_value(elem), "client_secret_basic") == 0) {
999
result = "client_secret_basic";
892
apr_byte_t oidc_metadata_provider_parse(request_rec *r, json_t *j_provider,
893
oidc_provider_t *provider) {
895
if (provider->issuer == NULL) {
896
/* get the "issuer" from the provider metadata */
897
oidc_json_object_get_string(r->pool, j_provider, "issuer",
898
&provider->issuer, NULL);
901
if (provider->authorization_endpoint_url == NULL) {
902
/* get a handle to the authorization endpoint */
903
oidc_json_object_get_string(r->pool, j_provider,
904
"authorization_endpoint", &provider->authorization_endpoint_url,
908
if (provider->token_endpoint_url == NULL) {
909
/* get a handle to the token endpoint */
910
oidc_json_object_get_string(r->pool, j_provider, "token_endpoint",
911
&provider->token_endpoint_url, NULL);
914
if (provider->userinfo_endpoint_url == NULL) {
915
/* get a handle to the user_info endpoint */
916
oidc_json_object_get_string(r->pool, j_provider, "userinfo_endpoint",
917
&provider->userinfo_endpoint_url, NULL);
920
if (provider->jwks_uri == NULL) {
921
/* get a handle to the jwks_uri endpoint */
922
oidc_json_object_get_string(r->pool, j_provider, "jwks_uri",
923
&provider->jwks_uri, NULL);
926
if (provider->registration_endpoint_url == NULL) {
927
/* get a handle to the client registration endpoint */
928
oidc_json_object_get_string(r->pool, j_provider,
929
"registration_endpoint", &provider->registration_endpoint_url,
933
if (provider->check_session_iframe == NULL) {
934
/* get a handle to the check session iframe */
935
oidc_json_object_get_string(r->pool, j_provider, "check_session_iframe",
936
&provider->check_session_iframe, NULL);
939
if (provider->end_session_endpoint == NULL) {
940
/* get a handle to the end session endpoint */
941
oidc_json_object_get_string(r->pool, j_provider, "end_session_endpoint",
942
&provider->end_session_endpoint, NULL);
945
if (provider->token_endpoint_auth == NULL) {
947
/* find a supported token_endpoint_auth_method in the provider metadata */
948
json_t *j_token_endpoint_auth_methods_supported = json_object_get(
949
j_provider, "token_endpoint_auth_methods_supported");
951
const char *token_endpoint_auth = NULL;
953
/* loop through the array provided by the issuer and see if there's a supported method */
954
if ((j_token_endpoint_auth_methods_supported != NULL)
955
&& (json_is_array(j_token_endpoint_auth_methods_supported))) {
958
i < json_array_size(j_token_endpoint_auth_methods_supported);
960
json_t *elem = json_array_get(
961
j_token_endpoint_auth_methods_supported, i);
962
if (!json_is_string(elem)) {
964
"unhandled in-array JSON object type [%d] in provider metadata for entry \"token_endpoint_auth_methods_supported\"",
969
/* take first supported method and prefer post over basic */
970
if ((apr_strnatcmp(json_string_value(elem),
971
"client_secret_post") == 0)
972
|| (apr_strnatcmp(json_string_value(elem),
973
"client_secret_basic") == 0)) {
974
token_endpoint_auth = json_string_value(elem);
980
/* store the method if found */
981
if (token_endpoint_auth != NULL) {
982
provider->token_endpoint_auth = apr_pstrdup(r->pool,
983
token_endpoint_auth);
1009
* get the metadata for a specified issuer
1011
* this fill the oidc_op_meta_t struct based on the issuer filename by reading and merging
1012
* contents from both provider metadata directory and client metadata directory
991
* parse the JSON conf metadata in to a oidc_provider_t struct
1014
apr_byte_t oidc_metadata_get(request_rec *r, oidc_cfg *cfg, const char *issuer,
1015
oidc_provider_t **result) {
1017
/* pointer to the parsed JSON metadata for the provider */
1018
json_t *j_provider = NULL;
1019
/* pointer to the parsed JSON metadata for the client */
1020
json_t *j_client = NULL;
1021
/* pointer to the parsed conf metadata for the client */
1022
json_t *j_conf = NULL;
1024
/* allocate space for a parsed-and-merged metadata struct */
1025
*result = apr_pcalloc(r->pool, sizeof(oidc_provider_t));
1026
/* convenient helper pointer */
1027
oidc_provider_t *provider = *result;
1029
/* see if we can get valid provider metadata (possibly bootstrapping with Discovery), if not, return FALSE */
1030
if (oidc_metadata_provider_get(r, cfg, issuer, &j_provider) == FALSE) {
1032
json_decref(j_provider);
1036
/* get the "issuer" from the provider metadata */
1037
oidc_json_object_get_string(r->pool, j_provider, "issuer",
1038
&provider->issuer, NULL);
1040
/* get a handle to the authorization endpoint */
1041
oidc_json_object_get_string(r->pool, j_provider, "authorization_endpoint",
1042
&provider->authorization_endpoint_url, NULL);
1044
/* get a handle to the token endpoint */
1045
oidc_json_object_get_string(r->pool, j_provider, "token_endpoint",
1046
&provider->token_endpoint_url, NULL);
1048
/* get a handle to the user_info endpoint */
1049
oidc_json_object_get_string(r->pool, j_provider, "userinfo_endpoint",
1050
&provider->userinfo_endpoint_url, NULL);
1052
/* get a handle to the jwks_uri endpoint */
1053
oidc_json_object_get_string(r->pool, j_provider, "jwks_uri",
1054
&provider->jwks_uri, NULL);
1056
/* get a handle to the client registration endpoint */
1057
oidc_json_object_get_string(r->pool, j_provider, "registration_endpoint",
1058
&provider->registration_endpoint_url, NULL);
1060
/* see if we can get valid config metadata */
1061
if (oidc_metadata_conf_get(r, cfg, issuer, &j_conf) == FALSE) {
1063
json_decref(j_provider);
1065
json_decref(j_conf);
993
apr_byte_t oidc_metadata_conf_parse(request_rec *r, oidc_cfg *cfg,
994
json_t *j_conf, oidc_provider_t *provider) {
1069
996
oidc_json_object_get_string(r->pool, j_conf, "client_jwks_uri",
1070
997
&provider->client_jwks_uri, cfg->provider.client_jwks_uri);