Package: tsgauth
tsgauthA collection of python base CERN SSO based authentication and authorisation tools used by the TSG. It provides methods for both users trying to access SSO protected sites in python and for sites to add SSO protection to their endpoints. It is minimal and tries to stay out of the way of the user as much as possible.The current version is 0.10.2It is pip installable bypip3installtsgauth==0.10.2
pip3installtsgauth[flask]==0.10.2#if you want flask modulespip3installtsgauth[fastapi]==0.10.2#if you want fastapi modulesVersion policy: The major version number will be incremented for any breaking changes. The minor version number will be incremented for any new features. The patch version number will be incremented for any bug fixes. The package is currently in development and will be so till it hits version 1.0.0, until then these rules will be a bit looser.It is intended that users use keyword arguments when passing into the function as the order of the arguements may change in minor versions with the exception of client_id which is always first. Only public methods and members (ie do not start with _) are considered part of the API and thus subject to the version policy. Changes to the internals will not be considered breaking changes but will be considered enough to bump the minor version number.Support requests can be raised on thegitlab issue trackeror by contacting Sam Harper on mattermost (prefered)Security WarningTo use this package securely there are two things you need to do:if you use the option to persist sessions ensure that the resulting authentication files stored in ~/.tsgauth are not compromised. Whoever has these files has the privileges they represent. They are created to be only read/writable by the user but if you copy them about, you need to ensure they are protected.if you use pip,always specify a version, iepip3 install tsgauth==0.10.1notpip3 install tsgauthto prevent asupply chain attack. This is a good idea for packages in general but is critical here. Otherwise you are trusting that a malicious actor has not compromised my pypi account and uploaded a malicious version of the package which could either intercept OTPs or send the resulting authentication files to a remote server. It would not be possible for them to access your password, just the auth session cookie/ access token. Note, it is not possible for anybody to upload new code as an existing version to pypi, iepip3 install tsgauth==0.10.1will always install the same code.Quick startHow to Access SSO CERN sites in python using TSGAuthThis is a minimal explaination for the impatient who just want to access a SSO protected website using python. For a more detailed explaination, please see the rest of this guide. TSGAuth is designed assuming you are using therequestsmodule but exposes methods which will work with any module which can make http requests assuming you can pass cookies and headers to it.There are different ways to access SSO protected sites on the cmdline, there are a series of classes in tsgauth.oidcauth for various types of authorsization and authentication mechanisms. They are all designed such thatauth=tsgauth.oidcauth.<AUTHCLASS>()r=requests.get(url,**auth.authparams())#note depending on the auth class, it may override your headers, thus you need to#pass in any headers you want in the authparams call, eg#**auth.authparams(headers={"Accept":"application/json"})will work for all of them.The only thing the user needs to do is select the correct class. To do this you need to know if the website (aka protected resource) you which to access is using session/cookie or token based authorisation.If its cookie based, you will need to use a SessionAuth derived class of which the only one istsgauth.oidcauth.KerbSessionAuth()which uses kerberos to authenticate. If it is token based, you need a TokenAuth class, of which there are three,tsgauth.oidcauth.KerbAuth(),tsgauth.oidcauth.ClientAuth()andtsgauth.oidcauth.DeviceAuth()depending on how you wish to authenticate.  You will also need to know the client id of the application you wish to access as well as its redirect_uri. If it is a confidential client, you will also need the client secret.Most users will wanttsgauth.oidcauth.KerbAuth()which uses kerberos to authenticate. Unlike the CERN sso-get-cookie and sso-get-token, tsgauth supports accounts with 2FA enabled (the author of this package has 2FA enabled...)examples using kerberosauth=tsgauth.oidcauth.KerbAuth("cms-tsg-frontend-client")r=requests.get("https://hltsupervisor.app.cern.ch/api/v0/thresholds",**auth.authparams())auth=tsgauth.oidcauth.KerbSessionAuth()r=requests.get("https://twiki.cern.ch/twiki/bin/view/CMS/TriggerStudies?raw=text",**auth.authparams())As a final heads up, the AuthClasses can persist cookies and tokens to disk so you dont need to reauthenticate every time. This is true by default for KerbSessionAuth, DeviceAuth classes. The directory should only be readable by the user and is~/.tsgauthby default but you can override it by setting theTSGAUTH_AUTHDIRenvironmental variable.These files should be protected as they grant access as you to the given application.Note, it is not an error for the application to fail to read/write to this directory, it will continue as is but log a warning. The logging level is controled by theTSGAUTH_LOGLEVELenvironmental variable and defaults toERROR. The writing of the authentication files is controled by the parameteruse_auth_filepassed in the constructor of the auth class. For convenience you can also force enabling / disabling of this feature globally by setting the environmental variablesTSGAUTH_FORCE_USE_AUTHFILE/TSGAUTH_FORCE_DONT_USE_AUTHFILEto 1.A summary of the enviromental variables is as follows:TSGAUTH_LOGLEVEL : logging level ("NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")TSGAUTH_AUTHDIR : directory where the auth files are written if requested to be (default: ~/.tsgauth))TSGAUTH_FORCE_USE_AUTHFILE : forces the authfile to be written/used (set to 1 to do this)TSGAUTH_FORCE_DONT_USE_AUTHFILE : forces the authfile to not be written/used  (set to 1 do this)Determing if a resource expects Session or Cookie based authorisationThe easiest way to find out how to service expects you to authenticate is ask the owner or review their documenation. As this is not always possible, you can open it up in a webbrowser and see how the browser is making requests.If you see the the requests to the protected api  have a header {"Authorization", "Bearer }" it is token based. You should also see the browser requesting said token, with something like:https://auth.cern.ch/auth/realms/cern/protocol/openid-connect/auth?client_id=cms-tsg-frontend-client&redirect_uri=https%3A%2F%2Fhltsupervisor.app.cern.ch%2F&state=8dbacbe6-e06e-4fb9-8699-eb87c136195a&response_mode=fragment&response_type=code&scope=openid&nonce=3d5ff976-fd51-43aa-8b0d-3a72c2782b20this gives your client_id (cms-tsg-frontend-client) and a valid redirect_uri (https://hltsupervisor.app.cern.ch/) which you can use to request a token.If you dont see anything like this, its session based (you'll probably see a cookie auth session or similar). Session Cookie auth is mainly done public services using confidential clients. The client (say an apache server which is interacting with the resource server on your behalf) handles the token exchange and the user never sees the token. It will instead issue you a cookie so identify you for the authentication session.Securing FastAPI sitesIf you wish to secure an endpoint on your fast api system, you just need to make your endpoint depend on tsgauth.fastapi.JWTBearerClaims. This will validate the user claims (unless validate_token=False) and make them available to your endpoint. Note: I've only recently started using fastapi so while I think this is a good way to do it, there may be better ways which more experienced fastapi users can suggest.fromtsgauth.fastapiimport@app.get("/api/v0/secure")defsecure_endpoint(claims=Depends(JWTBearerClaims("your-client-id"))):return{"claims":claims}This will validate the user claims with an audience of your_client_id and make the claims available to your endpoint. If you have no further need of the the claims info, you can put the depends in the decorator.You can see an example of this in the tests/test_fastapi.py file which is run as part of the unit testsSecuring Flask sitesIn python this was modeled after the flask-oidc package which is completely not recommended but when we started we ended up using due to very inadequate documenation. It requires the following variables to be set in your flask configurationapp.config.update({'OIDC_ISSUER':"https://auth.cern.ch/auth/realms/cern"'OIDC_JWKS_URI':"https://auth.cern.ch/auth/realms/cern/protocol/openid-connect/certs"'OIDC_CLIENT_ID':<yourclientid>})and then can be used as followsimporttsgauth.flaskoidcasoidc@application.route('/api/v0/secure',methods=['GET'])@oidc.accept_token(require_token=True)defsecure_endpoint():returnjsonify({"claims":g.oidc_token_info})You can see an example of this in the tests/test_flaskoidc.py file which is run as part of the unit tests