I'm building a Python application that needs to communicate with an OAuth service provider. The SP requires me to specify a callback URL. Specifying localhost obviously won't work. I'm unable to set up a public facing server. Any ideas besides paying for server/hosting? Is this even possible?
Two things:
The OAuth Service Provider in question is violating the OAuth spec if it's giving you an error if you don't specify a callback URL. callback_url is spec'd to be an OPTIONAL parameter.
But, pedantry aside, you probably want to get a callback when the user's done just so you know you can redeem the Request Token for an Access Token. Yahoo's FireEagle developer docs have lots of great information on how to do this.
Even in the second case, the callback URL doesn't actually have to be visible from the Internet at all. The OAuth Service Provider will redirect the browser that the user uses to provide his username/password to the callback URL.
The two common ways to do this are:
Create a dumb web service from within your application that listens on some port (say, http://localhost:1234/) for the completion callback, or
Register a protocol handler (you'll have to check with the documentation for your OS specifically on how to do such a thing, but it enables things like <a href="skype:555-1212"> to work).
(An example of the flow that I believe you're describing lives here.)
In case you are using *nix style system, create a alias like 127.0.0.1 mywebsite.dev in /etc/hosts (you need have the line which is similar to above mentioned in the file, Use http://website.dev/callbackurl/for/app in call back URL and during local testing.
This was with the Facebook OAuth - I actually was able to specify 'http://127.0.0.1:8080' as the Site URL and the callback URL. It took several minutes for the changes to the Facebook app to propagate, but then it worked.
This may help you:
http://www.marcworrell.com/article-2990-en.html
It's php so should be pretty straightforward to set up on your dev server.
I've tried this one once:
http://term.ie/oauth/example/
It's pretty simple. You have a link to download the code at the bottom.
localtunnel [port] and voila
http://blogrium.wordpress.com/2010/05/11/making-a-local-web-server-public-with-localtunnel/
http://github.com/progrium/localtunnel
You could create 2 applications? 1 for deployment and the other for testing.
Alternatively, you can also include an oauth_callback parameter when you requesting for a request token. Some providers will redirect to the url specified by oauth_callback (eg. Twitter, Google) but some will ignore this callback url and redirect to the one specified during configuration (eg. Yahoo)
So how I solved this issue (using BitBucket's OAuth interface) was by specifying the callback URL to localhost (or whatever the hell you want really), and then following the authorisation URL with curl, but with the twist of only returning the HTTP header. Example:
curl --user BitbucketUsername:BitbucketPassword -sL -w "%{http_code} %{url_effective}\\n" "AUTH_URL" -o /dev/null
Inserting for your credentials and the authorisation url (remember to escape the exclamation mark!).
What you should get is something like this:
200 http://localhost?dump&oauth_verifier=OATH_VERIFIER&oauth_token=OATH_TOKEN
And you can scrape the oath_verifier from this.
Doing the same in python:
import pycurl
devnull = open('/dev/null', 'w')
c = pycurl.Curl()
c.setopt(pycurl.WRITEFUNCTION, devnull.write)
c.setopt(c.USERPWD, "BBUSERNAME:BBPASSWORD")
c.setopt(pycurl.URL, authorize_url)
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.perform()
print c.getinfo(pycurl.HTTP_CODE), c.getinfo(pycurl.EFFECTIVE_URL)
I hope this is useful for someone!
Related
HttpPlatformHandler supports forwarding the auth token by enabling the forwardWindowsAuthToken setting in the web.config.
This sounds like a useful feature when needing to use Windows Integrated Authentication.
The document on this is very vague and does not go into explaining how one could use this token to get the authenticated user name.
If this setting is set to true, the token will be forwarded to the
child process listening on %HTTP_PLATFORM_PORT% as a header
'X-IIS-WindowsAuthToken' per request. It is the responsibility of that
process to call CloseHandle on this token per request. The default
value is false.
In my use-case, I needed to use Windows Integrated Authentication with Python, so did a setup with IIS fronting and using HTTP Platform Handler forward requests to Python.
The question is, how do I get the user name from the provided token in Python ?
The token in the 'X-IIS-WindowsAuthToken' header seems like a 3 char hex like 22b.
Okay, so I've researched this a bit and ended up reviewing how Microsoft.AspNetCore.Server.IISIntegrateion.AuthenticationHandler did it.
Then after figuring out one way, I wanted to post this answer so 1) I can find it later, 2) at least it's up on SO in case anyone else is wondering.
Okay, so the hex value is the handle and with the handle we can call impersonate user then get username, done.
All you need is the pywin32 package:
pip install pywin32
Complete example in Python:
import win32api
import win32security
if 'x-iis-windowsauthtoken' in request.headers.keys():
handle_str = request.headers['x-iis-windowsauthtoken']
handle = int(handle_str, 16) # need to convert from Hex / base 16
win32security.ImpersonateLoggedOnUser(handle)
user = win32api.GetUserName()
win32security.RevertToSelf() # undo impersonation
win32api.CloseHandle(handle) # don't leak resources, need to close the handle!
print(f"user name: {user}")
I'm currently attempting to use spotipy, a python3 module, to access and edit my personal Spotify premium account. I've followed the tutorial on https://github.com/plamere/spotipy/blob/master/docs/index.rst using the util.prompt_for_user_token method by entering the necessary parameters directly (username, client ID, secret ID, scope and redirect uri). Everything seems to be fine up to this part. My code (fillers for username, client id and client secret for security reasons) :
code
It opens up my default web browser and redirects me to my redirect url with the code in it. At this point, I copy and paste the redirect url (as prompted) and hit enter. It returns the following error:
Error
My redirect uri is 'http://google.com/' for this specific example. However, I've tried multiple redirect uris but they all seem to produce the same error for me. (and yes, I did set my redirect uri as whitespace for my application). I've spent hours trying to fix this issue by looking at online tutorials, trying different redirect urls, changing my code but have yet to make any progress. I'm hoping I am just overlooking a simple mistake here! Any feedback on how to fix this is much appreciated!
If it matters: I'm using the IDE PyCharm.
I had to use two different solutions to deal with the redirect_uri issue depending on which IDE I was using. For Jupyter Lab/Notebook, I could use a localhost for the redirect_url
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id="your_client_id", client_secret="your_client_secret", redirect_uri="https://localhost:8890/callback/", scope="user-library-read"))
For Google Colab, I had to use a publicly accessible website. I think "https://google.com/" should work but I used my band's website so I'd remember that the redirect_uri had to match the one in your Spotify Develop dashboard settings.
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id="your_client_id", client_secret="your_client_secret", redirect_uri="https://yourwebsite.com/", scope="user-library-read"))
I just ended up using my bands website because it was easier for me to remember. Make sure to go to the Spotify developer dashboard (https://developer.spotify.com/dashboard/applications) and match the redirect_uri with what you are planning to use at that time.
I think it is your redirect URL - working for me with:
import os
import spotipy.util as util
# credentials
user = 'username'
desired_scope = 'playlist-modify-private'
id = os.environ.get('SPOT_CLIENT')
secret = os.environ.get('SPOT_SECRET')
uri = 'https://localhost'
token = util.prompt_for_user_token(username=user,
scope=desired_scope,
client_id=id,
client_secret=secret,
redirect_uri=uri)
I think for your redirect url spotify requires the initial http(s) part - don't forget to add it to the white-list in your Spotify for Developers app too, as otherwise you will get 'invalid-redirect-uri'.
I have create a webproject Web2Py and would like user to access the pages on normal http:// instaed of http://.
Each time I type http://domain.pythonanywhere.com et redirect me to http://domain.pythonanywhere.com.
It taces 0.5 sec. to do the SSL check and I would like to avoid that.
This was as default:
## if SSL/HTTPS is properly configured and you want all HTTP requests to
## be redirected to HTTPS, uncomment the line below:
# request.requires_https()
PythonAnywhere dev here: that looks like a bug on our side. We "pin" HTTPS for our own site, so that people always go to https://www.pythonanywhere.com/, but it looks like that might have leaked over to customer sites.
Just for clarity -- if someone goes to http://yourusername.pythonanywhere.com/ then we won't initially force it to go to the https site -- they'll get the http one. But if they then go to https://yourusername.pythonanywhere.com, then their browser will remember that they have visited the https domain, so all future requests will redirect there.
That's actually generally good practice (it works around a number of security problems) but we shouldn't be forcing it on people.
[UPDATE] the bug is now fixed, many thanks to boje for pointing us at it :-) One caveat -- if you've ever visited your site over HTTPS before we applied the fix, then you'll still be forced to HTTPS. You need to clear your browser history to see the new unpinned behaviour.
I had an issue let http:// redirect to https:// And I found google group post on here. The following code maybe give you some ideas on your problem, Under db.py add:
############ FORCED SSL #############
from gluon.settings import global_settings
if global_settings.cronjob:
print 'Running as shell script.'
elif not request.is_https:
redirect(URL(scheme='https', args=request.args, vars=request.vars))
session.secure()
#####################################
I want to do some web scraping with GAE. (Infinite Campus Student Information Portal, fyi). This service requires you to login to get in the website.
I had some code that worked using mechanize in normal python. When I learned that I couldn't use mechanize in Google App Engine I ended up using urllib2 + ClientForm. I couldn't get it to login to the server, so after a few hours of fiddling with cookie handling I ran the exact same code in a normal python interpreter, and it worked. I found the log file and saw a ton of messages about stripping out the 'host' header in my request... I found the source file on Google Code and the host header was in an 'untrusted' list and removed from all requests by user code.
Apparently GAE strips out the host header, which is required by I.C. to determine which school system to log you in, which is why it appeared like I couldn't login.
How would I get around this problem? I can't specify anything else in my fake form submission to the target site. Why would this be a "security hole" in the first place?
App Engine does not strip out the Host header: it forces it to be an accurate value based on the URI you are requesting. Assuming that URI's absolute, the server isn't even allowed to consider the Host header anyway, per RFC2616:
If Request-URI is an absoluteURI, the host is part of the Request-URI.
Any Host header field value in the
request MUST be ignored.
...so I suspect you're misdiagnosing the cause of your problem. Try directing the request to a "dummy" server that you control (e.g. another very simple app engine app of yours) so you can look at all the headers and body of the request as it comes from your GAE app, vs, how it comes from your "normal python interpreter". What do you observe this way?
I'm attempting to implement a simple Single Sign On scenario where some of the participating servers will be windows (IIS) boxes. It looks like SPNEGO is a reasonable path for this.
Here's the scenario:
User logs in to my SSO service using his username and password. I authenticate him using some mechanism.
At some later time the user wants to access App A.
The user's request for App A is intercepted by the SSO service. The SSO service uses SPNEGO to log the user in to App A:
The SSO service hits the App A web page, gets a "WWW-Authenticate: Negotiate" response
The SSO service generates a "Authorization: Negotiate xxx" response on behalf of the user, responds to App A. The user is now logged in to App A.
The SSO service intercepts subsequent user requests for App A, inserting the Authorization header into them before passing them on to App A.
Does that sound right?
I need two things (at least that I can think of now):
the ability to generate the "Authorization: Negotiate xxx" token on behalf of the user, preferably using Python
the ability to validate "Authorization: Negotiate xxx" headers in Python (for a later part of the project)
This is exactly what Apple does with its Calendar Server. They have a python gssapi library for the kerberos part of the process, in order to implement SPNEGO.
Look in CalendarServer/twistedcaldav/authkerb.py for the server auth portion.
The kerberos module (which is a c module), doesn't have any useful docstrings, but PyKerberos/pysrc/kerberos.py has all the function definitions.
Here's the urls for the svn trunks:
http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk
http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk
Take a look at the http://spnego.sourceforge.net/credential_delegation.html tutorial. It seems to be doing what you are trying to do.
I've been searching quite some time for something similar (on Linux), that has lead me to this page several times, yet giving no answer. So here is my solution, I came up with:
The web-server is a Apache with mod_auth_kerb. It is already running in a Active Directory, single sign-on setup since quite some time.
What I was already able to do before:
Using chromium with single sign on on Linux (with a proper krb5 setup, with working kinit user#domain)
Having python connect and single sign on using sspi from the pywin32 package, with something like sspi.ClientAuth("Negotiate", targetspn="http/%s" % host)
The following code snippet completes the puzzle (and my needs), having Python single sign on with Kerberos on Linux (using python-gssapi):
in_token=base64.b64decode(neg_value)
service_name = gssapi.Name("HTTP#%s" % host, gssapi.C_NT_HOSTBASED_SERVICE)
spnegoMechOid = gssapi.oids.OID.mech_from_string("1.3.6.1.5.5.2")
ctx = gssapi.InitContext(service_name,mech_type=spnegoMechOid)
out_token = ctx.step(in_token)
buffer = sspi.AuthenticationBuffer()
outStr = base64.b64encode(out_token)