How to get username with CherryPy digest authentication - python

I have a CherryPy application running successfully using the built-in digest authentication tool and no session support. Now, I would like to expose additional features to certain users. Is it possible to obtain the currently-authenticated user from the authorization system?

You can use: cherrypy.request.login.
To quote:
When authentication is used during the request processing this is set
to ‘False’ if it failed and to the ‘username’ value if it succeeded.
The default ‘None’ implies that no authentication happened.
The whole HTTP Basic / Digest authentication in CherryPy is very nicely explained here (unfortunately the original blog no longer features this page, at least I couldn't find it - WayBack Machine to the rescue).

Found the user name encoded in the HTTP request header Authorization. I am able to parse it from there. If there's a "better" place to obtain the username, I'm open to improvements!

How about this...
params = auth_header.split(" ", 1)
items = parse_http_list(params)
paramsd = parse_keqv_list(items)
username = paramsd.get('username')
http://www.gitorious.org/forban/forban/blobs/1f9aff12551675f7cd8395f8bd0733cfc4c40784/lib/ext/cherrypy/lib/auth_digest.py
As I looked at it more this approach still uses auth header...
Andrew

Related

How to safely send a user data in API call

Created a Flash Restful API with various end points for my website. Some endpoints need the users username and password to get user specific data. I’m currently sending these as parameters in the API call but I’m assuming this isn’t secure so how does one do this safely?
There are plenty of differing ways to do this but it's generally accepted that using tokens, which can be revoked, are a more secure way of doing auth than using a username/password combo. This is due to the inability to retract a username/password if they got leaked.
I'd suggest reading the following blog by Miguel. He explains password authentication followed by tokens.
Miguel Grinberg
you can make a seperate api route that acts as a login and returns a sessionID/token on a successful login that can be used for authenticating to those endpoints you mentioned.

How do I access the Salesforce API when single-sign on is enabled?

I'm attempting to make SOQL queries to the Salesforce API using the Python salesforce_api and simple-salesforce modules. I had been making these requests with a client object:
client = Salesforce(username='MY_USERNAME',
password='MY_PASSWORD',
security_token='MY_SALESFORCE_SECURITY_TOKEN')
a = client.query("SELECT something FROM some_object_table WHERE some_condition")
However, my company recently restricted Salesforce sign-in through SSO only (you used to be able to login directly to Salesforce without SSO), and the funciton is throwing either:
simple_salesforce.exceptions.SalesforceAuthenticationFailed: INVALID_SSO_GATEWAY_URL: the single sign on gateway url for the org is invalid
Or:
salesforce_api.exceptions.AuthenticationMissingTokenError: Missing or invalid security-token provided.
depending on which module I use. I suspect this is because of the SSO implementation.
I've seen the docs about creating a new app through Okta, but I need to authenticate and access the API of an existing app. What is the best way to access this API with Okta IdP enabled? It there a way to have a get request to Okta return an access token for Salesforce?
Uh. It's doable but it's an art. I'll try to write it up but you should have a look at "Identity and Access Management" Salesforce certification, study guides etc. Try also asking at salesforce.stackexchange.com, might get better answers and Okta specialists.
I don't know if there's pure server-side access to Okta where you'd provide OAuth2 client, secret, username and password and it'd be silently passed to login.
If your app is a proper web application that needs human to operate - you can still make it work with SSO. You'd have to read about OAuth2 in general (you saw it on the web, all the "login with Google/Facebook/LinkedIn/Twitter/..." buttons) and then implement something like this or this. Human starts in your app, gets redirected to SF to enter username and password (you don't see password and you don't care whether he encountered normal SF login page or some SSO), on success he/she is redirected back and you receive info that'll let you obtain session id (sometimes called access token). Once you have access token you can make queries etc, it's just a matter of passing it as HTPP Authorization Bearer header (simple-salesforce docs mention session id at top of the examples).
Look, I know what I've written doesn't make much sense. Download Data Loader and try to use it. You might have to make it use custom domain on login but there is a way for it to still work, even though you have SSO enforced. Your goal would be to build similar app to how Data Loader does it. This might help a bit: https://stackoverflow.com/a/61820476/313628
If you need a true backend integration without human involved... tricky. That might be a management problem though. They should not enforce SSO on everybody. When Okta's down you're locked out of the org, no way to disable SSO. You should have a backup plan, some service account(s) that don't have SSO enforced. They might have crazy password requirements, maybe login only from office IP address, whatever. It's not a good idea to enforce SSO on everybody.
https://help.salesforce.com/articleView?id=sso_tips.htm
We recommend that you don’t enable SSO for Salesforce admins. If your
Salesforce admins are SSO users and your SSO server has an outage,
they have no way to log in to Salesforce. Make sure that Salesforce
admins can log in to Salesforce so that they can disable SSO if
problems occur.
(If you have a web app and it's embedded as Canvas in SF - there's another clean way to have the session id passed to you. Again - this works only if you have a human rather than backend integration)
If you check the profiles in SFDC and uncheck the box that requires SSO.
"is single sign-on Enabled [] Delegate username and password authentication to a corporate database instead of the salesforce.com user database. "

How to add login credential via python script?

I am sure this is an answered question somewhere, but I could not find a solution for me (if you know a duplicate feel free to mark it).
My goal is to query a RESTful API. To do that I need to authenticate. The only way available for me for this API is via web-browser.
Basically, I am loading URL which redirects to another URL. In the second URL, there is a form where I need to input username and password to authenticate. Currently, I input the credentials manually via a web browser.
My question is: Can I do this programmatically such that I don't have to manually input the credentials via a web browser?
Note: the webpage is not verified.
Attempt 1
I tried the following commands, but none worked:
curl -k -u username:password https://myurl:port
It did not return anything.
Attempt 2
BASE_URL = 'https://myurl:port'
username = 'username'
password = 'password'
r = requests.get(BASE_URL, auth=(username, password), verify=False)
print(r.status_code, r.reason)
it prints <Response [200]> but it does not authenticate. This is because when I try to query an API endpoint - it says I am unauthorized. When I input the credentials manually in the browser - then the endpoint query works.
Attempt 3
Finally, I thought (but did not do) I need some way to read the login page and input credentials by getting the html elements and then clicking log in (with selenium for example), but this seems too rough and error-prone. Maybe there is a more elegant way.
Any ideas of how I can do this?
Basically, I am loading URL which redirects to another URL. In the
second URL, there is a form where I need to input username and
password to authenticate
From your description it sounds like you are accessing an API using OAuth2 with the authorization code grant flow ?...which by design requires the user (=resource owner) to authorise (via the form) your app (=client) to access his/her data provided by the API (=resource server). in this case, using basic auth (Attempt 1 and 2) will not help you as the API expects a token, not username/password. you'd probably need a refresh token that does not expire and would allow your client to request a fresh access token each time it wants to access the API...
It all depends on the authentication mechanism used by your API...I'd first figure out if your API is indeed using OAuth2, and if so, learn about authentication flows (e.g. https://www.udemy.com/course/learn-oauth-2/) ...client credentials flow is probably what you'd want if the API allows for it...
update: Attempt 3 might be worth a try, i've never done it though. you might be able to send the credentials by submitting the corresponding form data via python requests...then that should in theory provide you with an authorization code which you can use to get a token...
Thanks for showing us your attempts.
If the attempt 2 returns 200 status code. It means it does work which means that basic auth works. Simple solution is to just pass auth=(username, password) to all of your api calls.
Or you can use requests.Session() to authenticate once and keep the session provided that server supports session authentication.
Hope this helps.

Which headers should I provide for authentication in GitHub API?

I'm trying to use Basic Authentication in GitHub API. I wrote something like this:
reqURL = "https://api.github.com/repos/user/repo"
pullreqsURL = urllib.request.Request(reqURL)
pullreqsURL.add_header("Authorization", "Basic " + str(base64.urlsafe_b64encode(b'Username:myAuthTokenORpass')) )
pullreqsURL.add_header("Content-Type", "application/json")
pullreqsURL.add_header("Accept", "application/json")
urllib.request.urlopen(pullreqsURL)
However, it keeps throwing HTTPError.
With commented 3rd line it goes well.
Well. I've solved it using personal token instead of user:pass
pullreqsURL.add_header("Authorization", "token >mytoken<" )
It should be possible to authenticate via Basic Authentication with username/password.
Quote from the link:
Via Username and Password
To use Basic Authentication with the GitHub API, simply send the
username and password associated with the account.
However, I don't know Python, so I don't know whether str(base64.urlsafe_b64encode(b'Username:myAuthTokenORpass')) is the proper way to Base64 encode username/password.
As you mentioned personal access tokens, it's also possible to authenticate via Basic Authentication, but with an access token instead of your real password.
This is explained in my first link as well.
Quote:
Via OAuth Tokens
Alternatively, you can use personal access
tokens or OAuth
tokens instead of your password.
curl -u username:token https://api.github.com/user
This approach is useful if your tools only support Basic
Authentication but you want to take advantage of OAuth access token
security features.
I'm using this approach with success in a project of mine.

Is it possible to use OAuth 2.0 without a redirect_uri or without setting up a complex server?

I got to transfer some files to a remote server for which I have to perform OAuth2.0 to get access token and then simply perform a POST request to upload the files.
Now I am too lazy to setup a Django project on cloud and then perform OAuth2 while there are not "too good" lib for that though.
So, I am thinking to perform OAuth2 using rauth lib as a simple python script without really setting up a server that accepts requests and all..
However, on the remote server profile, I need to provide a redirect_url and of course in the rauth client lib.
Are there any possible ways to do this authorization without really setting up a project on cloud..A simply python script is what I am looking for.
I'm the author and maintainer of rauth.
Rauth no longer enforces a redirect_uri, so if your provider allows it then you can forgo using it. However if you ultimate goal is not to setup a server, this should be doable even with a redirect_uri required by the provider. You can, for example, redirect to localhost where you could setup a minimal server using Flask or if the provider allows it, some other, arbitrary URL, e.g. Facebook provides https://www.facebook.com/connect/login_success.html for this purpose. And the provider you're using might have a similar scheme. Here's an example with rauth.
Another option is to use Bearer Auth with grant_type=password. All OAuth 2.0 providers are supposed to support Bearer Auth, but may not implement the password grant_type. This does not require a redirect_uri, instead you end up passing the server your user credentials and it should return an access token to you. If your provider allows Bearer Auth with grant_type of password, this is probably the ideal for you. Rauth 0.5.3 attempts to use Bearer Auth by default so all you have to do is pass in the grant_type. Be sure to update before giving this a go.
Here's a simple example:
# assume you have constructed an OAuth2Service object and bound it to `serv`
params = {'grant_type': 'password',
'username': 'foo',
'password': 'hunter2'}
s = service.get_auth_session(params=params)
r = s.get('https://example.com/api/some/endpoint')
Depending on the provider and what you want to do, it may require a little more investigation. However, hopefully this gives you something to start with.
Edit
I think my comment about password grant_type is a little confusing: I seem to be implying you have to use it with Bearer Auth (here by Bearer Auth I mean affixing the access token in the Authorization header in the Bearer format), but actually you don't. It's acceptable, although discouraged, to send the credentials along in the entity method[1]. If you're using rauth and find that authentication is not working as expected, you may need to disable Bearer Auth like this:
s = service.get_auth_session('/some/resource',
data={'code': code},
bearer_auth=False)
From the spec:
[1] "Clients SHOULD make authenticated requests with a bearer token using the Authorization request header field with the Bearer HTTP authorization scheme. Resource servers MUST support this method."

Categories