Authenticator: Bearer_token w. "query_parameter" selector consumes request body
marbergq opened this issue · comments
Preflight checklist
- I could not find a solution in the existing issues, docs, nor discussions.
- I agree to follow this project's Code of Conduct.
- I have read and am following this repository's Contribution Guidelines.
- This issue affects my Ory Network project.
- I have joined the Ory Community Slack.
- I am signed up to the Ory Security Patch Newsletter.
Describe the bug
GIven this rule
authenticators:
- handler: bearer_token
config:
check_session_url: http://check-session-host/...
token_from:
query_parameter: token
The upstream service will never see the body when the request is of Content-type: application/x-www-form-urlencoded
.
This is because return r.FormValue(*tokenLocation.QueryParameter)
(in helper/bearer.go
) will consume the body
Reproducing the bug
config.yaml:
api:
port: 6061
proxy:
port: 6060
access_rules:
repositories:
- file://./rules.1.json
authenticators:
noop:
enabled: true
bearer_token:
enabled: true
config:
check_session_url: http://localhost:6662/session
authorizers:
allow:
enabled: true
deny:
enabled: true
mutators:
noop:
enabled: true
rules.1.yaml
[
{
"id": "test",
"upstream": {
"url": "http://127.0.0.1:6662"
},
"match": {
"url": "http://127.0.0.1:6060/test",
"methods": ["POST"]
},
"authenticators": [
{
"handler": "bearer_token",
"config": {
"check_session_url": "http://127.0.0.1:6662/session",
"preserve_path": true,
"preserve_query": false,
"force_method": "GET",
"token_from": {
"query_parameter": "token"
}
}
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
}
]
run.sh
#!/bin/bash
set -euo pipefail
waitport() {
i=0
while ! nc -z localhost "$1" ; do
sleep 1
if [ $i -gt 10 ]; then
cat ./config.yaml
cat ./oathkeeper.log
exit 1
fi
i=$((i+1))
done
}
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
run_oathkekeper() {
killall oathkeeper || true
export OATHKEEPER_PROXY=http://127.0.0.1:6060
export OATHKEEPER_API=http://127.0.0.1:6061
go build -o . ../..
LOG_LEVEL=debug ./oathkeeper --config ./config.yaml serve > ./oathkeeper.log 2>&1 &
waitport 6060
waitport 6061
}
run_api(){
killall okapi || true
PORT=6662 go run ./okapi > ./api.log 2>&1 &
waitport 6662
}
SUCCESS_TEST=()
FAILED_TEST=()
run_test() {
label=$1
shift 1
result="0"
"$@" || result="1"
if [[ "$result" -eq "0" ]]; then
SUCCESS_TEST+=("$label")
else
FAILED_TEST+=("$label")
fi
}
function finish {
echo ::group::Config
cat ./config.yaml
cat ./rules.1.json
echo ::endgroup::
echo ::group::Log
cat ./oathkeeper.log
echo ::endgroup::
}
trap finish EXIT
run_oathkekeper
run_api
curl -X POST -f http://127.0.0.1:6662/test?token=token -F fk=fv -H "Content-Type: application/x-www-form-urlencoded" -i
kill %1 || true
trap - EXIT
okapi/main.go
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/julienschmidt/httprouter"
)
func main() {
router := httprouter.New()
router.POST("/test", test)
router.GET("/session", session)
port := os.Getenv("PORT")
if port == "" {
port = "6662"
}
server := http.Server{
Addr: fmt.Sprintf(":%s", port),
Handler: router,
}
if err := server.ListenAndServe(); err != nil {
panic(err)
}
}
func test(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
fmt.Printf("body was: %s", string(b))
_, _ = w.Write(b)
}
func session(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.WriteHeader(http.StatusOK)
}
$> ./run.sh
time=2023-05-24T14:07:31+02:00 level=warning msg=Access request denied because roundtrip failed audience=application error=map[message:net/http: HTTP/1.x transport connection broken: http: ContentLength=140 with Body length 0 stack_trace:
....
Relevant log output
time=2023-05-24T14:07:31+02:00 level=warning msg=Access request denied because roundtrip failed audience=application error=map[message:net/http: HTTP/1.x transport connection broken: http: ContentLength=140 with Body length 0 stack_trace:
Relevant configuration
[
{
"id": "test",
"upstream": {
"url": "http://127.0.0.1:6662"
},
"match": {
"url": "http://127.0.0.1:6060/test",
"methods": ["POST"]
},
"authenticators": [
{
"handler": "bearer_token",
"config": {
"check_session_url": "http://127.0.0.1:6662/session",
"preserve_path": true,
"preserve_query": false,
"token_from": {
"query_parameter": "token"
}
}
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
}
]
Version
0.40.3
On which operating system are you observing this issue?
None
In which environment are you deploying?
Kubernetes
Additional Context
No response