Package: eve-negotiable-auth
eve-negotiable-authAn advanced yet easy to use auth module for APIs built onEve.The auth class that ships with Eve,BasicAuth, allows users of your API to authenticate withBasic Authentication.  TheNegotiableAuthclass in this package extends this to allow the user to choose from any authentication scheme your API supports.  This allows for easy configuration and handling of multiple auth schemes - including schemes likeDigestwhich require negotiation.NOTE: This package is near-production ready.  Before calling it 1.0 it needs better docs and perhaps a bit more tweaking.  It is already in use in a number of production systems - but use at your own risk!Getting StartedThe steps are:Create a handler functions for each scheme you supportRegister those functions with AUTH_PARSERExtendNegotiableAuthand overrideprocess_claims()Step 1 - Create handler functionsTo handle a scheme you must define at least one function, usually two, which theauthparserlibrary will call.  You can name them however you like - authparser calls them user_record_fn and challenge_fnuser_record_fn(token, **kwargs)challenge_fn(**kwargs)[optional - seeauthparserfor details, mandatory for schemes likeDigest]This is best described with an example.  Let's say you want to handleBearertoken authorization.  When the time comes to validate the token, your user_record_fn will be called.  So let's create it.  I'll call ithandle_bearer:defhandle_bearer(token,**kwargs):# do stuff to validate the token# ...# if it checks out, populate the user record:record={'user':'someone@example.com','role':'employee'}# if there is a problem (if NegotiableAuth sees '_issues' then it will deny access):record={'_issues':{'token':'The token has expired.'}}returnrecordStep 2 - Register the handler functionsThe best place to do this is above the class definition you will create in step 3.  I will start by creating a file namedmy_auth.pyfromeve_negotiable_authimportNegotiableAuth,AUTH_PARSERfrom--whereveryoudefinedyourhandler--importhandle_bearerAUTH_PARSER.add_handler('Bearer',handle_bearer)Now when the time comes,NegotiableAuthwill know if it receives a request whoseAuthorizationheader has aBearertoken, it will call yourhandle_bearer()function.Step 3 - ExtendNegotiableAuthand overrideprocess_claims()TheNegotiableAuthclass is an abstract base class and cannot be used on its own.  You must make your own class that inherits from it.  There is only one function to override:process_claims().Building on themy_auth.pywe started in step 2:fromeve_negotiable_authimportNegotiableAuth,AUTH_PARSERfrom--whereveryoudefinedyourhandler--importhandle_bearerclassMyAuth(NegotiableAuth):def__init__(self):super(MyAuth,self).__init__()defprocess_claims(self,claims,allowed_roles,resource,method):authorized='user'inclaimsrole=claims.get('role')ifresouce='salary'androle!='employer':authorized=Falseifresource=='position'andmethod!='GET'androle!='employer':authorized=FalsereturnauthorizedThis is a too-simple example for illustration only.  The request will be authorized ifuserexists in claims, unless the request is forsalarythen only employers are allowed.  If it is aGETrequest forposition, it is allowed for everyone - only employers canPOST,PUT,DELETE, etc.There are many things you can do in your ownprocess_claims().  Please read theEve docsfor more details.The things you need to know:claimsis the record returned from your handler function.If the handler returns falsey, or dict with_issues, it will reject the request before your class'sprocess_claims()is calledyourprocess_claims()need only returnTrueorFalse, depending whether theclaimsis allowed in or not.As you see, you are in full control of what's inclaimsand how to determine whether to grant access based on what is in theclaims.allowed_roles,resource, andmethodare passed in from Eve depending on the request and what is in your Eve settings.If you are using Eve'sUser-Restricted Resource Access, process_claims() is where you will callself.set_request_auth_value()Wire it into your projectOnce you have defined your auth class, add it to your Eve app.  When you instantiate the app, pass the class name as theauthparam.app=Eve('app-name',auth=MyAuth)Beyond the BasicsWhenNegotiableAuthcalls your handler function, it passes the following kwargs toget_user_record()allowed_rolesresourcemethodrequest - the flask request objectWhen you define that function, have it return an dict with each member a claim (e.g. username, email, role).  If the function returns falsey, or a dict that has a member named_issues, then access will be denied.  To communicate issues back to the requestor, have_issuesbe a dict of name/value pairs, for example (this example has just one name/value):{'_issues':{'user':'This user does not exist.'}}get_challenge_header()- passed through to the scheme'schallenge_fnrequest...more docs coming soon...