I wrote a cherrypy server to facilitate a file download and I used cherrypy auth digest to authenticate it. The configuration for this is:
conf = {
'/getXML': {
'tools.auth_digest.on': True,
'tools.auth_digest.realm': None,
'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(USERS),
'tools.auth_digest.key': <some_key>
}
}
What is the role of that key?
Also, upon successful authentication, when I hit the server again it remembers login and does not prompt for credentials again. How can I ask for credentials for each and every request without remembering login?
Think of the key as a session id. You generate it once the user comes to your site...
cherrypy.session['_csrf_token'] = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(16))
then you set that id in the user's cookies and you compare the two keys to be sure you have the same user. That is the concept behind using the 'tools.sessions.on': True, setting in cherrypy. This allows you to know a user from one page to another in a stateless environment such as http.
https://cherrypy.readthedocs.org/en/3.3.0/refman/lib/auth_digest.html#cherrypy.lib.auth_digest.HttpDigestAuthorization.validate_nonce
**
validate_nonce(s, key)
Validate the nonce. Returns True if nonce was generated by synthesize_nonce() and the timestamp is not spoofed, else returns False.
s
A string related to the resource, such as the hostname of the server.
key
A secret string known only to the server.
Both s and key must be the same values which were used to synthesize the nonce we are trying to validate.
**
looks like forcing a logout with auth digest is not possible...
https://groups.google.com/d/msg/cherrypy-users/M-GUFH2mU_M/45zHnA5Y6XMJ
Here's more details on the digest authentication...
What is digest authentication?
But this is a simple authenication where you can force a logout...
How to logout from a simple web appl. in CherryPy, Python
Hope this helps!
Related
I tried so many methods, but none seem to work. Help me make a connection with LinkedIn using python. Issue in generating Access Token I received CODE but it doesn't work. I have python 3.9 Please post a sample of basic code that establishes a connection and gets a access Token. And which redirectUri I have to use. Can i use any website link for rediectUri.
I tried to check API through curl and Postman but didn't get solution its say Unauthorized Accesss.
https://github.com/ozgur/python-linkedin <---This is where I got some idea how to use API .To recievd Access token .
First solution valid for any (including free) applications, it useses so-called 3-Legged OAuth 2.0 Authentication:
Login to your account in the browser.
Create new application by this link.
If you already have application you may use it by selecting it here and changing its options if needed.
In application credentials copy Client ID and Client Secret, you'll need them later.
On your application's server side create Authorization request URL by next code and send/redirect it to client. If your Python code runs locally you may just open this URL in your browser with import webbrowser; webbrowser.open(url) code. Fill in all fields with your values too. There is redirect_uri in the code, this is URL where authorization response is sent back, for locally running script you have to run Python HTTP web server to retrieve result.
# Needs: python -m pip install requests
import requests, secrets
url = requests.Request(
'GET',
'https://www.linkedin.com/oauth/v2/authorization',
params = {
'response_type': 'code', # Always should equal to fixed string "code"
# ClientID of your created application
'client_id': 'REPLACE_WITH_YOUR_CLIENT_ID',
# The URI your users are sent back to after authorization.
# This value must match one of the OAuth 2.0 Authorized Redirect
# URLs defined in your application configuration.
# This is basically URL of your server that processes authorized requests like:
# https://your.server.com/linkedin_authorized_callback
'redirect_uri': 'REPLACE_WITH_REDIRECT_URL', # Replace this with your value
# state, any unique non-secret randomly generated string like DCEeFWf45A53sdfKef424
# that identifies current authorization request on server side.
# One way of generating such state is by using standard "secrets" module like below.
# Store generated state string on your server for further identifying this authorization session.
'state': secrets.token_hex(8).upper(),
# Requested permissions, below is just example, change them to what you need.
# List of possible permissions is here:
# https://learn.microsoft.com/en-us/linkedin/shared/references/migrations/default-scopes-migration#scope-to-consent-message-mapping
'scope': ' '.join(['r_liteprofile', 'r_emailaddress', 'w_member_social']),
},
).prepare().url
# You may now send this url from server to user
# Or if code runs locally just open browser like below
import webbrowser
webbrowser.open(url)
After user authorized your app by previous URL his browser will be redirected to redirect_uri and two fields code and state will be attached to this URL, code is unique authorization code that you should store on server, code expires after 30 minutes if not used, state is a copy of state from previous code above, this state is like unique id of your current authorization session, use same state string only once and generate it randomly each time, also state is not a secret thing because you send it to user inside authorization URL, but should be unique and quite long. Example of full redirected URL is https://your.server.com/linkedin_authorized_callback?code=987ab12uiu98onvokm56&state=D5B1C1348F110D7C.
Next you have to exchange code obtained previously to access_token by next code, next code should be run on your server or where your application is running, because it uses client_secret of your application and this is a secret value, you shouldn't show it to public, never share ClientSecret with anyone except maybe some trusted people, because such people will have ability to pretend (fake) to be your application while they are not.
# Needs: python -m pip install requests
import requests
access_token = requests.post(
'https://www.linkedin.com/oauth/v2/accessToken',
params = {
'grant_type': 'authorization_code',
# This is code obtained on previous step by Python script.
'code': 'REPLACE_WITH_CODE',
# This should be same as 'redirect_uri' field value of previous Python script.
'redirect_uri': 'REPLACE_WITH_REDIRECT_URL',
# Client ID of your created application
'client_id': 'REPLACE_WITH_YOUR_CLIENT_ID',
# Client Secret of your created application
'client_secret': 'REPLACE_WITH_YOUR_CLIENT_SECRET',
},
).json()['access_token']
print(access_token)
access_token obtained by previous script is valid for 60 days! So quite long period. If you're planning to use your application for yourself only or your friends then you can just pre-generate manually once in two months by hands several tokens for several people without need for servers.
Next use access_token for any API calls on behalf of just authorized above user of LinkedIn. Include Authorization: Bearer ACCESS_TOKEN HTTP header in all calls. Example of one such API code below:
import requests
print(requests.get(
'https://api.linkedin.com/v2/jobs',
params = {
# Any API params go here
},
headers = {
'Authorization': 'Bearer ' + access_token,
# Any other needed HTTP headers go here
},
).json())
More details can be read here. Regarding how your application is organized, there are 3 options:
Your application is running fully on remote server, meaning both authentication and running application (API calls) are done on some dedicated remote server. Then there is no problem with security, server doesn't share any secrets like client_secret, code, access_token.
Your application is running locally on user's machine while authentication is runned once in a while by your server, also some other things like storing necessary data in DataBase can be done by server. Then your server doesn't need to share client_secret, code, but shares access_token which is sent back to application to user's machine. It is also OK, then your server can keep track of what users are using your application, also will be able to revoke some or all of access_tokens if needed to block user.
Your application is fully run on local user's machine, no dedicated server is used at all. In this case all of client_secret, code, access_token are stored on user's machine. In this case you can't revoke access to your application of some specific users, you can only revoke all of them by regenerating client_secret in your app settings. Also you can't track any work of your app users (although maybe there is some usage statistics in your app settings/info pages). In this case any user can look into your app code and copy client_secret, unless you compile Python to some .exe/.dll/.so and encrypt you client secret there. If anyone got client_secret he can pretend (fake) to be your application meaning that if you app contacts other users somehow then he can try to authorize other people by showing your app interface while having some other fraudulent code underneath, basically your app is not that secure or trusted anymore. Also local code can be easily modified so you shouldn't trust your application to do exactly your code. Also in order to authorize users like was done in previous steps 5)-7) in case of local app you have to start Python HTTP Server to be able to retrieve redirected results of step 5).
Below is a second solution valid only if your application is a part of LinkedIn Developer Enterprise Products paid subscription, also then you need to Enable Client Credentials Flow in your application settings, next steps uses so-called 2-Legged OAuth 2.0 Authentication:
Login to your account in the browser.
Create new application by this link.
If you already have application you may use it by selecting it here and changing its options if needed.
In application credentials copy ClientID and ClientSecret, you'll need them later.
Create AccessToken by next Python code (put correct client id and client secret), you should run next code only on your server side or on computers of only trusted people, because code uses ClientSecret of your application which is a secret thing and shouldn't be showed to public:
# Needs: python -m pip install requests
import requests
access_token = requests.post(
'https://www.linkedin.com/oauth/v2/accessToken',
params = {
'grant_type': 'client_credentials',
'client_id': 'REPLACE_WITH_YOUR_CLIENT_ID',
'client_secret': 'REPLACE_WITH_YOUR_CLIENT_SECRET',
},
).json()['access_token']
print(access_token)
Copy access_token from previous response, it expires after 30 minutes after issue so you need to use previous script often to gain new access token.
Now you can do any API requests that you need using this token, like in code below (access_token is taken from previous steps):
import requests
print(requests.get(
'https://api.linkedin.com/v2/jobs',
params = {
# Any API params go here
},
headers = {
'Authorization': 'Bearer ' + access_token,
# Any other needed HTTP headers go here
},
).json())
More details can be read here or here.
My Python script needs to push files to Box every night, unattended. I've been reading as much as I can find about how machine-to-machine user-level authentication with Box in Python works, but I can't find any examples of performing the actual authentication in a Python script.
I found out how to encode what Box requires as a JWT payload here: JWT Claims. But, how do I use this JWT once I have it?
There is a very suggestive paragraph in the Box documentation about getting a user access token (JWT Authentication):
Your service will authenticate to Box by sending a JSON Web Token to the /token endpoint containing a JSON payload that includes the Client ID, enterprise_id or user_id, and additional claims, and sign it using the private key of an RSA keypair. Box then verifies the identity of your application using the public key specific to your application.
The problem is, I can't find any reference that tells me how to use the JWT once I have it. I'm pretty sure I make some call to https://api.box.com/oauth2/token, but how do I sign it with the private key, and what is the exact way of sending it in Python? E.g. do I use pycurl, or something else?
Once I have an access token I am able to authenticate using OAuth2, so that part is all right. There's just that piece in the middle I'm missing.
Please note I need to get a user token, not an enterprise-level token, so JWTAuth doesn't work for me.
You can do user-based authentication with JWTAUth. Instead of calling authenticate_instance, you use authenticate_app_user. Here is a code snippet:
from boxsdk import JWTAuth, Client
auth = JWTAuth(
client_id='CLIENT ID HERE',
client_secret='CLIENT SECRET HERE',
enterprise_id='USER_ID HERE',
jwt_key_id='JWT KEY HERE',
rsa_private_key_file_sys_path='PATH/TO/FILE',
rsa_private_key_passphrase=b'PASSPHRASE HERE'
)
access_token = auth.authenticate_app_user(type('',(object,),{"object_id": "USER_ID HERE"})())
client = Client(auth)
# ... etc
However, you still need to get your app authorized by a box admin for your enterprise.
I'm just now getting into authentication in my app, and all of the pyramid examples that I can find explain the straightforward parts very well, but handwave over the parts that don't make any sense to me.
Most of the examples look something like this:
login = request.params['login']
password = request.params['password']
if USERS.get(login) == password:
headers = remember(request, login)
return HTTPFound(location = came_from,
headers = headers)
And from init:
session_factory = UnencryptedCookieSessionFactoryConfig(
settings['session.secret']
)
authn_policy = SessionAuthenticationPolicy()
authz_policy = ACLAuthorizationPolicy()
Trying to track down the point in which the login actually happens, I'm assuming it's this one:
headers = remember(request, login)
It appears to me that what is going on is we're storing the username in the session cookie.
If I put this line in my app, the current user is magically logged in, but why?
How does pyramid know that I'm passing a username? It looks like I'm just passing the value of login. Further, this variable is named differently in different examples.
Even if it does know that it's a username, how does it connect it with the user ID? If I run authenticated_userid(request) afterwards, it works, but how has the system connected the username with the userid? I don't see any queries as part of the remember() documentation.
Pyramid's security system revolves around principals; your login value is that principal. It is up to your code to provide remember() with a valid principal name; if your login name filled in the form is used as your principal, then that's great. If you are using an email address but use a database primary key as the principal string, then you'd have to map that yourself.
What exactly remember() does depends on your authentication policy; it is up to the policy to 'know' from request to request what principal you asked it to remember.
If you are using the AuthTktAuthenticationPolicy policy, then the principal value is stored in a cryptographically signed cookie; your next response will have a Set-Cookie header added. Then next time a request comes in with that cookie, provided it is still valid and the signature checks out, the policy now 'knows' what principle is making that request.
When that request then tries to access a protected resource, Pyramid sees that a policy is in effect, and asks that policy for the current authenticated principle.
I am using Flask-Restful to build a REST service. The iOS device will then connect to this REST backend to sync the local data.
The service will be accessed over a https connection.
The REST service is stateless and the user has to authenticate upon each request. Hence the username and password will be sent in clear format to the REST service. The backend will hash the password and check against the existing hashed password in the database.
api.add_resource(Records, '/rest/records/<string:email>/<string:password>/<string:ios_sync_timestamp>')
Now one problem I see with this approach is that the username and password are in clear format as part of the GET url. The server log will obviously track this. Now if my backend was ever hacked into, the log files would compromise all the usernames and passwords.
What is the best solution to this? I was thinking maybe sending username and password as POST arguments, but how do I that with GET requests then?
class Records(Resource):
def get(self, email, password, ios_sync_timestamp):
pass
def post(self, email, password, ios_sync_timestamp):
pass
To authenticate each requests with a username and password like you want, you should use: Basic Authentication.
To use it, it's pretty simple and it works with all HTTP methods (GET, POST, ...). You just need to add an HTTP header into the request:
Authorization: Basic <...>
The <...> part is the username:password encoded in base64.
For example, if your login is foo and your password is bar. The HTTP header should have this line:
`Authorization: Basic Zm9vOmJhcg==`
Through your HTTPS connection, it's secure.
EDIT: Using Flask, you can use Flask HTTP auth to achieve this "automatically".
Another solution instead of the Basic Auth in each call as suggested by Sandro Munda is to generate an API Key using a POST to first check credentials request and then passing it in the request headers. Then you can verify it in each API handler for a strict-grained checking or application-wide using a #before_request handler.
Workflow
Client sends a POST to the server with the credentials (username/pass)
Server replies with an API Key. Like an hexdigest of something secret.
from now on
Each time the client needs to send an API request it adds an header (let's call it X-API-Key with the API Key.
I'm trying to connect to the reporting api to get some data of the percentage of usage of the emails of the users of a domain. I want to do it as a cron job every day so I need some method to authentificate as the admin of the domain authomatically without any admins interaction.
Now I'm using administrator password and login like this
url = 'https://www.google.com/hosted/services/v1.0/reports/ReportingData'
url_login='https://www.google.com/accounts/Clientlogin'
auth_request = urllib.urlencode({'accountType': 'HOSTED','Email': _ADMIN,'Passwd': _PASSW})
login = doPost(url_login, auth_request)
for line in login.split('\n'):
array = line.split('=',2)
if array[0]=='SID':
token = array[1]
_REQUEST_TEMPLATE = ('<?xml version="1.0" encoding="UTF-8"?>\n'
'<rest xmlns="google:accounts:rest:protocol"\n'
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n'
' <type>%(type)s</type>\n'
' <token>%(token)s</token>\n'
' <domain>%(domain)s</domain>\n'
' <date>%(date)s</date>\n'
' <reportType>daily</reportType>\n'
' <reportName>%(reportName)s</reportName>\n'
'</rest>\n')
but I don't want to store the admin's password. I have tried to use Oatuh 2.0 but it seems that I always need the admin's interaction.
Is there any way to do it using consumer_key and consumer_secret?? or any other alternative?
Thanks!
You have to store the auth cerentials somwhere - no matter if its a ssl cert authorization, cookie authorization or user/pass credentials - they always have to be available to the scpript/program that is going to use them. If you dont want to store them in the script itself, you might want to store them in configuration file, and make the script read them from there, store in variable and use as needed. You can even store them in the database, but then you have to store database credentials, and so on, and so forth.