Skip to content

Commit

Permalink
Fixed encoding in tken files (text files) and token utils
Browse files Browse the repository at this point in the history
Corrected typo in logSupport comment
  • Loading branch information
mambelli committed Jul 10, 2023
1 parent 04e61c5 commit 98b9679
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 45 deletions.
14 changes: 7 additions & 7 deletions frontend/glideinFrontendElement.py
Original file line number Diff line number Diff line change
Expand Up @@ -1146,12 +1146,13 @@ def refresh_entry_token(self, glidein_el):
pwd_file, scope=scope, duration=duration, identity=identity
)
# NOTE: Sensitive information. Uncomment only in development machines.
# cmd = "/usr/sbin/frontend_condortoken %s" % glidein_site
# tkn_str = subprocessSupport.iexe_cmd(cmd, useShell=True)
# logSupport.log.debug("tkn_str= %s" % tkn_str)
with tempfile.NamedTemporaryFile(mode="wb", delete=False, dir=tkn_dir) as fd:
# # cmd = "/usr/sbin/frontend_condortoken %s" % glidein_site
# tkn_str = subprocessSupport.iexe_cmd(cmd, useShell=True)
# logSupport.log.debug("tkn_str= %s" % tkn_str)
# The token file is read as text file below. Writing fixed to be consistent
with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=tkn_dir) as fd:
os.chmod(fd.name, 0o600)
fd.write(tkn_str)
fd.write(tkn_str.encode())
os.replace(fd.name, tkn_file)
logSupport.log.debug("created token %s" % tkn_file)
elif os.path.exists(tkn_file):
Expand All @@ -1160,8 +1161,7 @@ def refresh_entry_token(self, glidein_el):
tkn_str += line
except Exception as err:
logSupport.log.warning("failed to create %s" % tkn_file)
for i in sys.exc_info():
logSupport.log.warning("%s" % i)
logSupport.log.warning("Error details: %s" % traceback.format_exc())

return tkn_str

Expand Down
2 changes: 1 addition & 1 deletion lib/logSupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def __init__(self, filename, maxDays=1, minDays=0, maxMBytes=10, backupCount=5,
self.compression = compression.lower()
except AttributeError:
pass
# bz2 compression can be implementes with encoding='bz2-codec' in BaseRotatingHandler
# bz2 compression can be implemented with encoding='bz2-codec' in BaseRotatingHandler
mode = "a"
BaseRotatingHandler.__init__(self, filename, mode, encoding=None)
self.backupCount = backupCount
Expand Down
62 changes: 25 additions & 37 deletions lib/token_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,17 @@
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

from glideinwms.lib import logSupport
from glideinwms.lib import defaults, logSupport
from glideinwms.lib.subprocessSupport import iexe_cmd

# 2/3 compatibility helpers
# Inspired by http://python3porting.com/problems.html#nicer-solutions

if sys.version_info[0] < 3:

def byt(x):
return x

else:
import codecs

def byt(x):
return codecs.latin_1_encode(x)[0]


def un_byt(data):
if not isinstance(data, str):
data = data.decode()
return data.strip()


def token_file_expired(token_file):
"""
Check validity of token exp and nbf claim.
Do not check signature, audience, or other claims
Args:
token_file: (str) a filename containing a jwt
token_file(Path or str): a filename containing a jwt (a text file w/ default encoding is expected)
Returns:
bool: True if exp in future or absent and nbf in past or absent,
Expand All @@ -75,7 +55,7 @@ def token_str_expired(token_str):
Do not check signature, audience, or other claims
Args:
token_str: (str) a string containing a jwt
token_str(str): string containing a jwt
Returns:
bool: True if exp in future or absent and nbf in past or absent,
Expand All @@ -93,22 +73,24 @@ def token_str_expired(token_str):
logSupport.log.error("Expired token: %s" % e)
except Exception as e:
logSupport.log.exception("Unknown exception decoding token: %s" % e)
logSupport.log.debug(f"Faulty token: {token_str}")
return expired


def simple_scramble(data):
"""Undo the simple scramble of HTCondor
simply XOR with 0xdeadbeef
Using defaults.BINARY_ENCODING (latin-1) to have a 1-to-1 characted-byte correspondence
Source: https://github.com/CoffeaTeam/jhub/blob/master/charts/coffea-casa-jhub/files/hub/auth.py#L196-L235
Args:
data: binary string to be unscrambled
data(bytearray): binary string to be unscrambled
Returns:
str: an HTCondor scrambled binary string
bytearray: an HTCondor scrambled binary string
"""
outb = byt("")
outb = "".encode(defaults.BINARY_ENCODING)
deadbeef = [0xDE, 0xAD, 0xBE, 0xEF]
ldata = len(data)
lbeef = len(deadbeef)
Expand All @@ -119,7 +101,7 @@ def simple_scramble(data):
datum = data[i]
rslt = datum ^ deadbeef[i % lbeef]
b1 = struct.pack("H", rslt)[0]
outb += byt("%c" % b1)
outb += ("%c" % b1).encode(defaults.BINARY_ENCODING)
return outb


Expand All @@ -129,29 +111,34 @@ def derive_master_key(password):
Source: https://github.com/CoffeaTeam/jhub/blob/master/charts/coffea-casa-jhub/files/hub/auth.py#L196-L235
Args:
password: (str) an unscrambled HTCondor password
password(bytes): an unscrambled HTCondor password (bytes-like: bytes, bytearray, memoryview)
Returns:
str: an HTCondor encryption/decryption key
"""

# Key length, salt, and info fixed as part of protocol
hkdf = HKDF(
algorithm=hashes.SHA256(), length=32, salt=byt("htcondor"), info=byt("master jwt"), backend=default_backend()
algorithm=hashes.SHA256(),
length=32,
salt="htcondor".encode(defaults.BINARY_ENCODING),
info="master jwt".encode(defaults.BINARY_ENCODING),
backend=default_backend(),
)
return hkdf.derive(password)
# HKDF.derive() requires bytes and returns bytes
return hkdf.derive(password).decode(defaults.BINARY_ENCODING)


def sign_token(identity, issuer, kid, master_key, duration=None, scope=None):
"""Assemble and sign an idtoken
Args:
identity: (str) who the token was generated for
issuer: (str) idtoken issuer, typically HTCondor Collector
kid: (str) Key ID
master_key: (str) encryption key
duration: (int, optional) number of seconds IDTOKEN is valid. Default: infinity
scope: (str, optional) permissions IDTOKEN has. Default: everything
identity(str): who the token was generated for
issuer(str): idtoken issuer, typically HTCondor Collector
kid(str): Key ID
master_key(str): encryption key
duration(int, optional): number of seconds IDTOKEN is valid. Default: infinity
scope(str, optional): permissions IDTOKEN has. Default: everything
Returns:
str: a signed IDTOKEN
Expand Down Expand Up @@ -248,4 +235,5 @@ def create_and_sign_token(pwd_file, issuer=None, identity=None, kid=None, durati
master_key = derive_master_key(obfusicated)
scope = "condor:/READ condor:/WRITE condor:/ADVERTISE_STARTD condor:/ADVERTISE_SCHEDD condor:/ADVERTISE_MASTER"
idtoken = sign_token(identity, issuer, kid, master_key, scope=scope)
print(un_byt(idtoken))
# idtoken is str
print(idtoken)

0 comments on commit 98b9679

Please sign in to comment.