I want to access an API endpoint which requires OpenAM authentication.
If I am trying to directly access this API endpoint, it will redirect (302) to OpenAM Auth page.
I am able to get a valid OpenAM token using https://github.com/jathanism/python-opensso.
But I am not getting how to use that valid token in-order to access the API endpoint.
I am trying to do this with Python.
If your API is protected by a policy agent, then the solution is simple, just include the session ID as a session cookie in the incoming request:
Cookie: iPlanetDirectoryPro=<sessionId-obtained-via-python-opensso
iPlanetDirectoryPro is the default name of the session cookie, it may be called differently in your environment.
Related
We have two Django backend applications running on GCP, let’s call it A and B. Both of these applications have a URL which can be accessed via web and many of the endpoints are secured, i.e; you require to be logged in to access the endpoint. Apart from the user authenticated URLs, I want a secure endpoint (let’s call it /server-secure) in application server B to be accessible ONLY by application server A. Which means I need to authorise and verify requests coming in at /server-secure URL to make sure they are coming from server A.
I would like to use the server A’s metadata to generate a signed instance token which I will use to verify the identity of the server. This is not an issue, because I can easily achieve this using Google Auth python library:
import google.auth
import google.oauth2.id_token
import google.auth.transport.requests
request = google.auth.transport.requests.Request()
target_audience = "https://pubsub.googleapis.com"
token = google.oauth2.id_token.fetch_id_token(request, target_audience)
I have also been able to decode the token on the other end:
from google.oauth2 import id_token
request = google.auth.transport.requests.Request()
print(id_token.verify_token(token, request))
My main issue is that I would like the communication to happen only and only if server A has a certain service account attached. There is one way to check this; which is to use the email key in the decoded token dictionary and check if it’s value is equal to some service account, but just out of curiosity, is there a better way to this?
Or, is it possible to create custom role (like "access-to-server-B") and authorise the request ONLY if the service account contains this specific role???
I'm trying to use the Lyft rides python API to access Lyft data. Specifically, I'm trying to access the ride estimate endpoint .
from lyft_rides.auth import ClientCredentialGrant
from lyft_rides.session import Session
from lyft_rides.client import LyftRidesClient
auth_flow = ClientCredentialGrant(client_id=MY_ID, client_secret=MY_SECRET, scopes="public")
session = auth_flow.get_session()
client = LyftRidesClient(session)
response = client.get_cost_estimates(start_latitude=start_lat, start_longitude=start_long, end_latitude=end_lat, end_longitude=end_long)
However, the surge rate in the response data is always 0, even during surge hours, and I've diagnosed that it's because I'm not utilizing the 3-legged authentication.
From the lyft developer docs,
3-Legged flow for accessing user-specific endpoints.
To make ride
requests or otherwise access user data, the user must grant you
access. Users who don't have a Lyft account will be prompted to create
a new account if they are directed through the following flow.
From the python docs,
Authorization
If you need access to a Lyft user’s account in order to make requests
on their behalf, you will go through a “3-legged” flow. In this case,
you will need the user to grant access to your application through the
OAuth 2.0 Authorization Code flow. See Lyft API docs.
The Authorization Code flow is a two-step authorization process. The
first step is having the user authorize your app and the second
involves requesting an OAuth 2.0 access token from Lyft. This process
is mandatory if you want to take actions on behalf of a user or access
their information.
from lyft_rides.auth import AuthorizationCodeGrant
auth_flow = AuthorizationCodeGrant(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_PERMISSION_SCOPES,
)
auth_url = auth_flow.get_authorization_url()
Navigate the user to the auth_url where they can grant access to your
application. After, they will be redirected to a redirect_url with the
format REDIRECT_URL?code=UNIQUE_AUTH_CODE. Use this redirect_url to
create a session and start LyftRidesClient.
session = auth_flow.get_session(redirect_url)
client = LyftRidesClient(session)
credentials = session.oauth2credential
Keep credentials information in a secure data store and reuse them to
make API calls on behalf of your user. The SDK will handle the token
refresh for you automatically when it makes API requests with a
LyftRidesClient.
Question
I'm trying to automate the python request within a script. Given that the 3rd leg of the authentication requires manually visiting a url and obtaining a code, is it possible to do this through a script?
[Full Disclosure: I'm one of Lyft's Developer Advocates]
The only way to get that data is by requesting therides.request scope is through the 3-legged OAuth flow (sorry about that). However, you only need to request this external authorization once if you ask for the offline scope as part of the initial authorization. If you have that scope requested initially, you can use refresh_tokens as outlined here and not get prompted for the external URL:
https://developer.lyft.com/docs/authentication#section-step-5-refreshing-the-access-token
If you're only using this script locally I'd recommend going through this authorization once and then building in refresh token logic into your script if your token has expired. Hope that helps!
I'm trying to connect to Mojio REST api authenticated with OAuth2 with Python server code. Here's the 'manual' from Mojio: https://docs.moj.io/#/document/view/doc_oauth
I'm doing the second option there 'Authorization Code'. I don't understand what is the 'redirect_uri' parametr for. What should I pass there when I'm developing on localhost?
Thanks
You might want to consider using the "Resource Owner Password Credentials Grant" vs normal UI based oAuth workflows. This allows you to capture the username and password in your application and authenticate with those credentials instead of a UI (which can be challenging if you are on a server). Of course this depends on your specific requirements.
To login, via "Resource Owner" flow...
HTTP POST
Uri:
https://accounts.moj.io/oauth2/token
Body:
grant_type=password&username=USERNAME&password=PASSWORD&redirect_uri=REDIRECT_URI&client_id=CLIENTID&client_secret=CLIENTSECRET&scope=SCOPE
Content-Type:
application/x-www-form-urlencoded
This token you get back will be short lived, I would recommend getting a refresh token (longer lifetime):
To get a refresh token:
HTTP POST
Uri:
https://accounts.moj.io/oauth2/token
Body:
grant_type=refresh_token&refresh_token=API_TOKEN_YOU_GOT_FROM_LOGIN&redirect_uri=REDIRECT_URI&client_id=CLIENTID&client_secret=CLIENTSECRET
Content-Type:
application/x-www-form-urlencoded
I'm developing an iOS app and using Django for backend. There are two apps I'm using in Django
Django OAuth Toolkit to support OAuth authentication
Python Social Auth to support social authentication
The social authentication process should be:
GET localhost/login/{application}
Authentication on Application site
Redirect to localhost/complete/{application}
Fetch {application}'s access token
Create a new user with my server's access token, and associate it with {application}'s access token
Redirect to localhost/accounts/profile
Then, I can use my server's access token to communicate with {application}.
But the client will see that the browser start with localhost/login/{application} and end with localhost/accounts/profile, and still don't know what is my server's access token, so my question is how to pass the access token to the client?
One solution is that redirect with access token as localhost/accounts/profile?token=MyServerToken, but how to add parameter when redirecting to profile url?
You likely already have what you need on the Django session for your user in question. That is, provided you are using the session middleware (auth of this type is nearly impossible without it), your identity provider specific tokens will usually be populated in the extra_data dict on the SocialUser model for the specific provider in question.
For example, assuming you have a reference to the Django user model (lets call it user):
access_token = user.social_auth.get(provider='google-oauth2').extra_data['access_token']
Unfortunately the specifics will vary depending on the backend you're working with. Remember that these tools are designed to let users authenticate against your app rather than to let you perform arbitrary actions against the product-specific APIs exposed by the various identity providers.
As for passing these tokens to the client, I'd need to know more about your use case. Chances are the identity provider in question set some session cookies on the client during its authentication flow. For example, if you sign in with Facebook, they set a few cookies which are automatically retrieved by the Facebook client-side javascript API. As such, there's no explicit sharing of tokens necessary between the server and the client.
Otherwise, if you must do it yourself, store them on a secure session cookie as follows:
response.set_cookie(social_auth_tokens,
value=your_data_here,
max_age=None, #cookie will expire at end of user session
expires=None,
path='/',
domain=None, #only readable by this domain
secure=True, #only transmitted over https
httponly=False) #readable by scripts running on the page
You should not pass the access token in the query string like /?token=my_token. Its not a secure way and definitely not recommended.
Some other approaches you can use are:
Approach-1: Setting server_access_token in response headers
You can set the access token in the response headers and send it using HTTPS protocol.
The token will be sent once and consumed by the client. Since the response headers are not passed in the subsequent requests, the token will be passed only once to the client. Client will then use it to make further requests by setting the token in the request headers.
class MySocialApplicationRedirectView(View):
def get(self, request, *args, **kwargs):
# Here, write your code to fetch the {application}'s access token,
# creating a new user with your server's access token, and then
# associating it with {application}'s access token
# assign the response to a variable and set the access token as a header in the response
response = HttpResponseRedirect('/accounts/profile/')
response['X-Auth-Token'] = 'my_server_access_token'
# can also use the below name as 'X-' prefixed headers are deprecated
# response['Auth-Token'] = 'my_server_access_token'
return response
Client can then retrieve the token from the headers and use this token to make further requests. In further requests, he must send the access token in request headers.
Approach-2: Setting server_access_token as a cookie
Another option is to set the server_access_token cookie in your response as #Ben mentioned.
response.set_cookie() would set the server_access_token cookie in the response and then the client can read the cookie and send this in further requests in the request headers.
class MySocialApplicationRedirectView(View):
def get(self, request, *args, **kwargs):
# Here, write your code to fetch the {application}'s access token,
# creating a new user with your server's access token, and then
# associating it with {application}'s access token
# assign the response to a variable and set the access token as a cookie in the response object
response = HttpResponseRedirect('/accounts/profile/')
response.set_cookie(key, value='my_server_access_token', ..other parameters )
return response
Note: For safety and security, all requests (both to obtain and use the tokens) must use HTTPS endpoints.
It does not answer your specific question, but I've solved similar problem using TastyPie. It was very straightforward, didn't have to handle more than one application though, but since it provides an API for any given application, shouldn't be a problem.
buddies
One of my GAE restful service needs login with admin account. And I'm writing an automation script in python for testing this service. The script simply do a HTTP POST and then check the returned response. The difficult part for me is how to authenticate the test script as an admin user.
I created an admin account for testing purpose. But I'm not sure how to use that account in my test script. Is there a way that my test script can use oath2 or other approach to authenticate itself as a test admin account?
Ok I think this might be what you are looking for, client libraries to authenticate and yeah I believe appengine now recommends using the oauth2 for any kind of authentication:
https://developers.google.com/accounts/docs/OAuth2#libraries
Then you get an auth token where you pass in headers on your restful request like:
# Your authenticated request
Authorization: Bearer TokenHere
Then in your handler you get it like:
try:
user = oauth.get_current_user('https://www.googleapis.com/auth/userinfo')
except NotAllowedError:
user = None
# then from the first link you should be able to access if
user.is_current_user_admin()
This is how I authenticate on android, but I only do this once and store it in session and just enable cookie jar on the httpclient.