Skip to content

Instantly share code, notes, and snippets.

@brianv0
Created February 14, 2020 02:53
Show Gist options
  • Save brianv0/9609748b8b77daf6d974598f5dee197c to your computer and use it in GitHub Desktop.
Save brianv0/9609748b8b77daf6d974598f5dee197c to your computer and use it in GitHub Desktop.
Prepare session for Redis
# Inject a session oauth2_proxy redis session store
import base64
import hashlib
import json
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
def encrypt_field(field: str, oauth2_secret: str) -> bytes:
secret_key_encoded = oauth2_secret
secret_key = base64.urlsafe_b64decode(secret_key_encoded)
backend = default_backend()
iv = os.urandom(16)
cipher = Cipher(algorithms.AES(secret_key), modes.CFB(iv), backend=backend)
encryptor = cipher.encryptor()
cipher_text: bytes = encryptor.update(field.encode("utf-8")) + encryptor.finalize()
encrypted_field = iv + cipher_text
return base64.b64encode(encrypted_field)
def prepare_session(prefix: str, oauth2_secret: str, token: str, email: str) -> Tuple[str, bytes]:
# prepare ticket and ticket secret
ticket_id = hashlib.sha1(os.urandom(16)).hexdigest()
secret = os.urandom(16)
secret_b64 = base64.urlsafe_b64encode(secret).decode().rstrip("=")
ticket = f"{prefix}-{ticket_id}.{secret_b64}"
# serialize session
session_obj = {
"IDToken": encrypt_field(token, oauth2_secret).decode(),
"Email": encrypt_field(email, oauth2_secret).decode(),
"User": encrypt_field(email, oauth2_secret).decode(),
"CreatedAt": "2020-01-01T06:00:00Z",
"ExpiresOn": "2020-01-01T07:00:00Z",
}
session_payload_str = json.dumps(session_obj)
# encrypt session
backend = default_backend()
cipher = Cipher(algorithms.AES(secret), modes.CFB(secret), backend=backend)
encryptor = cipher.encryptor()
encrypted_oauth2_session = encryptor.update(session_payload_str.encode()) + encryptor.finalize()
# return ticket and encrypted session
return ticket, encrypted_oauth2_session
ticket, encrypted_session = prepare_session(
"_oauth2_proxy", # OAUTH2_PROXY_COOKIE_NAME
"w8SfzQKjoE4Jfrdn9yggaVd2hf9OIwzl", # OAUTH2_PROXY_COOKIE_SECRET
"eyJ...(id token)", # ID token
"john@example.com", # Email from ID token
)
handle = ticket.split(".")[0]
# SETEX <handle> 3600 <encrypted_session>
@brianv0
Copy link
Author

brianv0 commented Feb 14, 2020

When oauth2_proxy is configured with --skip-jwt-bearer-tokens, you can also specify
--skip-session-tickets and use a session ticket in place of a full JWT. This can be useful
for APIs when JWTs are large.

A user could get a ticket in two ways: a ticket can be extracted from a cookie, or
a ticket and session can be constructed from a JWT and injected into the redis store,
if you have the oauth2_proxy cookie secret and cookie name.

This is an example of preparing a session object for storage in redis and returning
the ticket used to encrypt it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment