def makeHawkExt(self): """ Make an 'ext' for Hawk authentication """ o = self.options c = o.get('credentials', {}) if c.get('clientId') and c.get('accessToken'): ext = {} cert = c.get('certificate') if cert: if six.PY3 and isinstance(cert, six.binary_type): cert = cert.decode() if isinstance(cert, six.string_types): cert = json.loads(cert) ext['certificate'] = cert if 'authorizedScopes' in o: ext['authorizedScopes'] = o['authorizedScopes'] # .encode('base64') inserts a newline, which hawk doesn't # like but doesn't strip itself return utils.makeB64UrlSafe(utils.encodeStringForB64Header(utils.dumpJson(ext)).strip()) else: return {}
def makeHawkExt(self): """ Make an 'ext' for Hawk authentication """ o = self.options c = o.get('credentials', {}) if c.get('clientId') and c.get('accessToken'): ext = {} cert = c.get('certificate') if cert: if six.PY3 and isinstance(cert, six.binary_type): cert = cert.decode() if isinstance(cert, six.string_types): cert = json.loads(cert) ext['certificate'] = cert if 'authorizedScopes' in o: ext['authorizedScopes'] = o['authorizedScopes'] # .encode('base64') inserts a newline, which hawk doesn't # like but doesn't strip itself return utils.makeB64UrlSafe( utils.encodeStringForB64Header(utils.dumpJson(ext)).strip()) else: return {}
def test_makeb64urlsafe(): expected = b'-_' actual = subject.makeB64UrlSafe('+/') assert expected == actual
def createTemporaryCredentials(clientId, accessToken, start, expiry, scopes, name=None): """ Create a set of temporary credentials Callers should not apply any clock skew; clock drift is accounted for by auth service. clientId: the issuing clientId accessToken: the issuer's accessToken start: start time of credentials (datetime.datetime) expiry: expiration time of credentials, (datetime.datetime) scopes: list of scopes granted name: credential name (optional) Returns a dictionary in the form: { 'clientId': str, 'accessToken: str, 'certificate': str} """ for scope in scopes: if not isinstance(scope, six.string_types): raise exceptions.TaskclusterFailure('Scope must be string') # Credentials can only be valid for 31 days. I hope that # this is validated on the server somehow... if expiry - start > datetime.timedelta(days=31): raise exceptions.TaskclusterFailure('Only 31 days allowed') # We multiply times by 1000 because the auth service is JS and as a result # uses milliseconds instead of seconds cert = dict( version=1, scopes=scopes, start=calendar.timegm(start.utctimetuple()) * 1000, expiry=calendar.timegm(expiry.utctimetuple()) * 1000, seed=utils.slugId() + utils.slugId(), ) # if this is a named temporary credential, include the issuer in the certificate if name: cert['issuer'] = utils.toStr(clientId) sig = ['version:' + utils.toStr(cert['version'])] if name: sig.extend([ 'clientId:' + utils.toStr(name), 'issuer:' + utils.toStr(clientId), ]) sig.extend([ 'seed:' + utils.toStr(cert['seed']), 'start:' + utils.toStr(cert['start']), 'expiry:' + utils.toStr(cert['expiry']), 'scopes:' ] + scopes) sigStr = '\n'.join(sig).encode() if isinstance(accessToken, six.text_type): accessToken = accessToken.encode() sig = hmac.new(accessToken, sigStr, hashlib.sha256).digest() cert['signature'] = utils.encodeStringForB64Header(sig) newToken = hmac.new(accessToken, cert['seed'], hashlib.sha256).digest() newToken = utils.makeB64UrlSafe( utils.encodeStringForB64Header(newToken)).replace(b'=', b'') return { 'clientId': name or clientId, 'accessToken': newToken, 'certificate': utils.dumpJson(cert), }
def test_makeb64urlsafe(self): expected = b'-_' actual = subject.makeB64UrlSafe('+/') self.assertEqual(expected, actual)
def createTemporaryCredentials(clientId, accessToken, start, expiry, scopes, name=None): """ Create a set of temporary credentials Callers should not apply any clock skew; clock drift is accounted for by auth service. clientId: the issuing clientId accessToken: the issuer's accessToken start: start time of credentials (datetime.datetime) expiry: expiration time of credentials, (datetime.datetime) scopes: list of scopes granted name: credential name (optional) Returns a dictionary in the form: { 'clientId': str, 'accessToken: str, 'certificate': str} """ for scope in scopes: if not isinstance(scope, six.string_types): raise exceptions.TaskclusterFailure('Scope must be string') # Credentials can only be valid for 31 days. I hope that # this is validated on the server somehow... if expiry - start > datetime.timedelta(days=31): raise exceptions.TaskclusterFailure('Only 31 days allowed') # We multiply times by 1000 because the auth service is JS and as a result # uses milliseconds instead of seconds cert = dict( version=1, scopes=scopes, start=calendar.timegm(start.utctimetuple()) * 1000, expiry=calendar.timegm(expiry.utctimetuple()) * 1000, seed=utils.slugId().encode('ascii') + utils.slugId().encode('ascii'), ) # if this is a named temporary credential, include the issuer in the certificate if name: cert['issuer'] = utils.toStr(clientId) sig = ['version:' + utils.toStr(cert['version'])] if name: sig.extend([ 'clientId:' + utils.toStr(name), 'issuer:' + utils.toStr(clientId), ]) sig.extend([ 'seed:' + utils.toStr(cert['seed']), 'start:' + utils.toStr(cert['start']), 'expiry:' + utils.toStr(cert['expiry']), 'scopes:' ] + scopes) sigStr = '\n'.join(sig).encode() if isinstance(accessToken, six.text_type): accessToken = accessToken.encode() sig = hmac.new(accessToken, sigStr, hashlib.sha256).digest() cert['signature'] = utils.encodeStringForB64Header(sig) newToken = hmac.new(accessToken, cert['seed'], hashlib.sha256).digest() newToken = utils.makeB64UrlSafe(utils.encodeStringForB64Header(newToken)).replace(b'=', b'') return { 'clientId': name or clientId, 'accessToken': newToken, 'certificate': utils.dumpJson(cert), }