Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix encoding issue for username and password #184

Merged
merged 5 commits into from
Nov 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/workflows/build_and_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,23 @@ jobs:

- name: Install Configmaps and Secrets
run: |
wait_for_pod_log() {
while [[ $(kubectl logs $1 | grep $2) == "" ]]; do echo "waiting 5 more seconds for '$2' to appear in logs of pod '$1'..." && sleep 5; done
echo "Pod '$1' logs contains '$2'"
}
# because the sidecar pods signal ready state before we actually opened up all watching subprocesses, we wait some more time
sleep 15
sleep 20
echo "Installing resources..."
kubectl apply -f "test/resources/resources.yaml"
sleep 15
pods=("sidecar" "sidecar-5xx")
resources=("sample-configmap" "sample-secret-binary" "absolute-configmap" "relative-configmap" "url-configmap-500" "url-configmap-basic-auth" "sample-configmap")
for p in ${pods[*]}; do
for r in ${resources[*]}; do
wait_for_pod_log $p $r
done
done
# 5 more seconds after the last thing appeared in the logs.
sleep 5
- name: Retrieve pod logs
run: |
kubectl logs sidecar > /tmp/sidecar.log
Expand All @@ -97,6 +109,7 @@ jobs:
kubectl cp sidecar:/tmp/absolute/absolute.txt /tmp/absolute.txt
kubectl cp sidecar:/tmp/relative/relative.txt /tmp/relative.txt
kubectl cp sidecar:/tmp/500.txt /tmp/500.txt || true
kubectl cp sidecar:/tmp/secured.txt /tmp/secured.txt

echo "Downloading resource files from sidecar-5xx..."
kubectl cp sidecar-5xx:/tmp-5xx/hello.world /tmp/5xx/hello.world
Expand All @@ -108,6 +121,7 @@ jobs:
kubectl cp sidecar-5xx:/tmp/absolute/absolute.txt /tmp/5xx/absolute.txt
kubectl cp sidecar-5xx:/tmp-5xx/relative/relative.txt /tmp/5xx/relative.txt
kubectl cp sidecar-5xx:/tmp-5xx/500.txt /tmp/5xx/500.txt
kubectl cp sidecar-5xx:/tmp-5xx/secured.txt /tmp/5xx/secured.txt

- name: Verify files
run: |
Expand All @@ -118,6 +132,8 @@ jobs:
diff test/kubelogo.png /tmp/secret-kubelogo.png &&
echo -n "This absolutely exists" | diff - /tmp/absolute.txt &&
echo -n "This relatively exists" | diff - /tmp/relative.txt &&
echo -n "allowed" | diff - /tmp/secured.txt &&
echo -n '{"detail":"Not authenticated"}' | diff - /tmp/5xx/secured.txt &&
[ ! -f /tmp/500.txt ] && echo "No 5xx file created" &&
ls /tmp/script_result &&
echo -n "Hello World!" | diff - /tmp/5xx/hello.world &&
Expand All @@ -126,4 +142,4 @@ jobs:
echo -n "This absolutely exists" | diff - /tmp/5xx/absolute.txt &&
echo -n "This relatively exists" | diff - /tmp/5xx/relative.txt &&
echo -n "500" | diff - /tmp/5xx/500.txt &&
ls /tmp/5xx/script_result
ls /tmp/5xx/script_result
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ If the filename ends with `.url` suffix, the content will be processed as a URL
| `REQ_TIMEOUT` | How many seconds to wait for the server to send data before giving up for `.url` triggered requests or requests to `REQ_URI` (does not apply to k8s api requests) | false | `10` | float |
| `REQ_USERNAME` | Username to use for basic authentication for requests to `REQ_URL` and for `*.url` triggered requests | false | - | string |
| `REQ_PASSWORD` | Password to use for basic authentication for requests to `REQ_URL` and for `*.url` triggered requests | false | - | string |
| `REQ_BASIC_AUTH_ENCODING` | Which encoding to use for username and password as [by default it's undefined](https://datatracker.ietf.org/doc/html/rfc7617) (e.g. `utf-8`). | false | `latin1` | string |
| `SCRIPT` | Absolute path to shell script to execute after a configmap got reloaded. It runs before calls to `REQ_URI` | false | - | string |
| `ERROR_THROTTLE_SLEEP` | How many seconds to wait before watching resources again when an error occurs | false | `5` | integer |
| `SKIP_TLS_VERIFY` | Set to `true` to skip tls verification for kube api calls | false | - | boolean |
Expand All @@ -83,4 +84,4 @@ If the filename ends with `.url` suffix, the content will be processed as a URL
| `IGNORE_ALREADY_PROCESSED` | Ignore already processed resource version. Avoid numerous checks on same unchanged resource. req kubernetes api >= v1.19 | false | `false` | boolean |
| `LOG_LEVEL` | Set the logging level. (DEBUG, INFO, WARN, ERROR, CRITICAL) | false | `INFO` | string |
| `LOG_FORMAT` | Set a log format. (JSON or LOGFMT) | false | `JSON` | string |
| `LOG_TZ` | Set the log timezone. (LOCAL or UTC) | false | `LOCAL` | string |
| `LOG_TZ` | Set the log timezone. (LOCAL or UTC) | false | `LOCAL` | string |
12 changes: 8 additions & 4 deletions src/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
import os
import subprocess
from datetime import datetime
from logger import get_logger

import requests
from requests.adapters import HTTPAdapter
from requests.auth import HTTPBasicAuth
from requests.packages.urllib3.util.retry import Retry

from logger import get_logger

CONTENT_TYPE_TEXT = "ascii"
CONTENT_TYPE_BASE64_BINARY = "binary"

REQ_RETRY_TOTAL = 5 if os.getenv("REQ_RETRY_TOTAL") is None else int(os.getenv("REQ_RETRY_TOTAL"))
REQ_RETRY_CONNECT = 10 if os.getenv("REQ_RETRY_CONNECT") is None else int(os.getenv("REQ_RETRY_CONNECT"))
REQ_RETRY_READ = 5 if os.getenv("REQ_RETRY_READ") is None else int(os.getenv("REQ_RETRY_READ"))
REQ_RETRY_BACKOFF_FACTOR = 1.1 if os.getenv("REQ_RETRY_BACKOFF_FACTOR") is None else float(os.getenv("REQ_RETRY_BACKOFF_FACTOR"))
REQ_RETRY_BACKOFF_FACTOR = 1.1 if os.getenv("REQ_RETRY_BACKOFF_FACTOR") is None else float(
os.getenv("REQ_RETRY_BACKOFF_FACTOR"))
REQ_TIMEOUT = 10 if os.getenv("REQ_TIMEOUT") is None else float(os.getenv("REQ_TIMEOUT"))

# Tune default timeouts as outlined in
Expand Down Expand Up @@ -102,8 +105,9 @@ def request(url, method, enable_5xx=False, payload=None):

username = os.getenv("REQ_USERNAME")
password = os.getenv("REQ_PASSWORD")
encoding = 'latin1' if not os.getenv("REQ_BASIC_AUTH_ENCODING") else os.getenv("REQ_BASIC_AUTH_ENCODING")
if username and password:
auth = (username, password)
auth = HTTPBasicAuth(username.encode(encoding), password.encode(encoding))
else:
auth = None

Expand Down Expand Up @@ -165,4 +169,4 @@ def execute(script_path):
logger.debug(f"Script stderr: {result.stderr}")
logger.debug(f"Script exit code: {result.returncode}")
except subprocess.CalledProcessError as e:
logger.error(f"Script failed with error: {e}")
logger.error(f"Script failed with error: {e}")
9 changes: 9 additions & 0 deletions test/resources/resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,12 @@ metadata:
findme: "yup"
data:
500.txt.url: "http://dummy-server/500"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: url-configmap-basic-auth
labels:
findme: "yup"
data:
secured.txt.url: "http://dummy-server/secured"
49 changes: 30 additions & 19 deletions test/resources/sidecar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,23 @@ spec:
mountPath: /opt/script.sh
subPath: script.sh
env:
- name: LABEL
value: "findme"
- name: FOLDER
value: /tmp/
- name: RESOURCE
value: both
- name: SCRIPT
value: "/opt/script.sh"
- name: LABEL
value: "findme"
- name: FOLDER
value: /tmp/
- name: RESOURCE
value: both
- name: SCRIPT
value: "/opt/script.sh"
- name: REQ_USERNAME
value: "user1"
- name: REQ_PASSWORD
value: "abcdefghijklmnopqrstuvwxyz"
- name: REQ_BASIC_AUTH_ENCODING
# the python server we're using for the tests expects ascii encoding of basic auth credentials, hence we can't use non-ascii characters in the password or username
value: "ascii"
- name: LOG_LEVEL
value: "DEBUG"
volumes:
- name: shared-volume
emptyDir: {}
Expand All @@ -86,16 +95,18 @@ spec:
mountPath: /opt-5xx/script.sh
subPath: script.sh
env:
- name: LABEL
value: "findme"
- name: FOLDER
value: /tmp-5xx/
- name: RESOURCE
value: both
- name: SCRIPT
value: "/opt-5xx/script.sh"
- name: ENABLE_5XX
value: "true"
- name: LABEL
value: "findme"
- name: FOLDER
value: /tmp-5xx/
- name: RESOURCE
value: both
- name: SCRIPT
value: "/opt-5xx/script.sh"
- name: ENABLE_5XX
value: "true"
- name: LOG_LEVEL
value: "DEBUG"
volumes:
- name: shared-volume
emptyDir: {}
Expand Down Expand Up @@ -129,4 +140,4 @@ spec:
ports:
- port: 80
targetPort: 80
name: http
name: http
20 changes: 18 additions & 2 deletions test/server/server.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from fastapi import FastAPI
import uvicorn
from fastapi import Depends, FastAPI, status, HTTPException
from fastapi.logger import logger
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.responses import PlainTextResponse

app = FastAPI()

basic_auth_scheme = HTTPBasic()


@app.get("/", status_code=200)
def read_root():
Expand All @@ -27,3 +31,15 @@ async def read_item():
@app.post("/503", status_code=503)
async def read_item():
return 503


@app.get("/secured", status_code=200, response_class=PlainTextResponse)
async def read_secure_data(auth: HTTPBasicCredentials = Depends(basic_auth_scheme)):
if auth.username != 'user1' or auth.password != 'abcdefghijklmnopqrstuvwxyz':
logger.warning("[WARN] wrong auth: %s : %s ", auth.username, auth.password)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Incorrect user (${auth.username}) or password (${auth.password})",
headers={"WWW-Authenticate": "Basic"},
)
return 'allowed'