Coverage Report

Created: 2026-09-04 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/handle/dpop.c
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
/***************************************************************************
21
 * Copyright (C) 2017-2026 ZmartZone Holding BV
22
 * All rights reserved.
23
 *
24
 * DISCLAIMER OF WARRANTIES:
25
 *
26
 * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
27
 * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
28
 * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
29
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NOR ARE THERE ANY
30
 * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
31
 * USAGE.  FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
32
 * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
33
 * WILL BE UNINTERRUPTED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
34
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
36
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 * @Author: Hans Zandbelt - hans.zandbelt@openidc.com
41
 */
42
43
#include "handle/handle.h"
44
#include "mod_auth_openidc.h"
45
#include "proto/proto.h"
46
#include "util/util.h"
47
48
#include <ap_mmn.h>
49
50
0
#define OIDC_DPOP_PARAM_URL "url"
51
0
#define OIDC_DPOP_PARAM_NONCE "nonce"
52
0
#define OIDC_DPOP_PARAM_METHOD "method"
53
54
1
int oidc_dpop_request(request_rec *r, const oidc_cfg_t *c) {
55
1
  int rc = HTTP_BAD_REQUEST;
56
1
  char *s_url = NULL;
57
1
  char *s_access_token = NULL;
58
1
  char *s_nonce = NULL;
59
1
  char *s_method = NULL;
60
1
  char *s_dpop = NULL;
61
1
  const char *s_response = NULL;
62
1
  oidc_json_t *json = NULL;
63
1
  char *remote_ip = NULL;
64
65
1
#if AP_MODULE_MAGIC_AT_LEAST(20111130, 0)
66
1
  remote_ip = r->useragent_ip;
67
#else
68
  remote_ip = r->connection->remote_ip;
69
#endif
70
71
1
  if (!oidc_cfg_dpop_api_enabled_get(c)) {
72
1
    oidc_error(r, "DPoP hook called but the DPoP API is not enabled in %s", OIDCDPoPMode);
73
1
    goto end;
74
1
  }
75
76
  /* try to make sure that the proof-of-possession semantics are preserved */
77
0
  if ((_oidc_strnatcasecmp(remote_ip, r->connection->local_ip) != 0) &&
78
0
      (apr_table_get(r->subprocess_env, "OIDC_DPOP_API_INSECURE") == 0)) {
79
0
    oidc_warn(
80
0
        r,
81
0
        "reject DPoP creation request from remote host: you should create a separate virtual (sub)host "
82
0
        "that requires client certificate authentication to allow and proxy this request (remote_ip=%s, "
83
0
        "r->connection->local_ip=%s)",
84
0
        remote_ip, r->connection->local_ip);
85
0
    rc = HTTP_UNAUTHORIZED;
86
0
    goto end;
87
0
  }
88
89
  /* retrieve the access token parameter */
90
0
  oidc_util_url_parameter_get(r, OIDC_REDIRECT_URI_REQUEST_DPOP, &s_access_token);
91
0
  if (s_access_token == NULL) {
92
0
    oidc_error(r, "\"access_token\" value to the \"%s\" parameter is missing",
93
0
         OIDC_REDIRECT_URI_REQUEST_DPOP);
94
0
    goto end;
95
0
  }
96
97
  /* retrieve the URL parameter */
98
0
  oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_URL, &s_url);
99
0
  if (s_url == NULL) {
100
0
    oidc_error(r, "\"url\" parameter is missing");
101
0
    goto end;
102
0
  }
103
104
  /* retrieve the optional nonce parameter */
105
0
  oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_NONCE, &s_nonce);
106
107
  /* parse the optional HTTP method parameter */
108
0
  oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_METHOD, &s_method);
109
0
  if (_oidc_strnatcasecmp(s_method, "post") == 0)
110
0
    s_method = "POST";
111
0
  else if ((_oidc_strnatcasecmp(s_method, "get") == 0) || (s_method == NULL))
112
0
    s_method = "GET";
113
114
  /* create the DPoP header value */
115
0
  if ((oidc_proto_dpop_create(r, c, s_url, s_method, s_access_token, s_nonce, &s_dpop) == FALSE) ||
116
0
      (s_dpop == NULL)) {
117
0
    oidc_error(r, "creating the DPoP proof value failed");
118
0
    rc = HTTP_INTERNAL_SERVER_ERROR;
119
0
    goto end;
120
0
  }
121
122
  /* assemble and serialize the JSON response object */
123
0
  json = oidc_json_object();
124
0
  oidc_json_object_set_new(json, OIDC_HTTP_HDR_DPOP, oidc_json_string(s_dpop));
125
0
  s_response = oidc_json_encode(r->pool, json, OIDC_JSON_COMPACT | OIDC_JSON_PRESERVE_ORDER);
126
127
  /* return the serialized JSON response */
128
0
  rc = oidc_util_http_send(r, s_response, _oidc_strlen(s_response), OIDC_HTTP_CONTENT_TYPE_JSON, OK);
129
130
1
end:
131
132
1
  if (json)
133
0
    oidc_json_decref(json);
134
135
1
  return rc;
136
0
}