Making Twitter, Tastypie, Django, XAuth and iOS work to Build Django-based Access Permissions - iphone

I will build an iOS application whose functionality will be based on access permissions provided by a Django REST application.
Django manages the permissions for the activities in the iOS app. User A can do Work A if he/she is permitted. Permissions will be queried via ASIHTTPRequest to a REST API served by Django Tastypie.
There is no registration. Users will just be able to login via Twitter. XAuth will be used to present a login screen for users.
There are 2 types of users. For example purposes, there will be Type 1 and Type 2. Type 1 will be ordinary user who can only browse data in the iOS app.
Type 2 user can submit/edit data.
That's it theoretically. However...I don't know where to start!!
The biggest roadblock:
How can I hook Twitter XAuth with Django's user backend via Tastypie?
If I know this then I can query the necessary permissions.
Thanks in advance!

I've done something similar with django + tastypie and facebook login for iOS.
Authentication
Log the user in using whatever means you will, get the access_token.
Create a GET request tastypie endpoint to which you will pass the accesstoken as a query string.
On the server side validate etc... and then create your own internal "tastypie" token and return that in the response to the get request e.g:
class GetToken(ModelResource):
"""
Authenticates the user via facebook and returns an APIToken for them.
"""
class Meta(object):
queryset = ApiKey.objects.all()
resource_name = 'authenticate'
fields = ['user', 'key']
allowed_methods = ['get']
authorization = Authorization()
authentication = FacebookAuthentication()
def prepend_urls(self):
"""We override this to change default behavior
for the API when using GET to actually "create" a resource,
in this case a new session/token."""
return [
url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()),
self.wrap_view('_create_token'), name="api_get_token"),
]
def _create_token(self, request, **kwargs):
"""Validate using FacebookAuthentication, and create Api Token if authenticated"""
self.method_check(request, allowed=['get'])
# This checks that the user is authenticated on facebook and also creates the user
# if they have not been created.
self.is_authenticated(request)
self.throttle_check(request)
bundle = self.build_bundle(obj=None, request=request)
bundle = self.obj_create(bundle, request, **kwargs)
bundle = self.full_dehydrate(bundle)
self.log_throttled_access(request)
return self.create_response(request, bundle.data)
def obj_create(self, bundle, request=None, **kwargs):
"""Create a new token for the session"""
bundle.obj, created = ApiKey.objects.get_or_create(user=request.user)
return bundle
Pass the returned API key on all subsequent calls, can either be as a query string param again or I set it on the Authorisation header for every call.
Make sure ALL the other resources you want to have authentication on have ApiKeyAuthentication() set in the Meta.
class ThingResource(ModelResource):
class Meta:
queryset = Thing.objects.all()
resource_name = 'thing'
authentication = ApiKeyAuthentication()
Authorisation
So now you know on the server side that the user is who they say they are, what is this user allowed to do? Thats what the authorisation meta is all about.
You probably want Django Authorisation in which case you can just use the normal permissioning schemes for users, or you could roll your own. It's pretty simple.

amrox has a nice example on how to hook a custom fork of django-oauth-plus that supports xAuth into tastypie. I imagine it can be tweaked to suit your purposes.

Related

403 Forbidden while accessing Leycloak rest API with a valid user credentials

I have set up a Keycloak server and a user named 'sample' is given permissions to access the rest ADMIN APIs, I granted permissions to the relevant realm and client_id. And I'm able to access the rest APIs using the postman service using this user credentials 'sample/sample'.
so through Angular application, I was trying to access the API that fetches the roles in a specific realm. since not all the login user will have the rest admin access, I'm using the user credentials(sample/sample) that have the access to admin API, but when I try to access the API, the APIs are forbidden,
this.getKeycloakAccessToken().subscribe((Tokres:any)=>{
console.log('accessToken: ', Tokres.body.access_token);
if(Tokres && Tokres.status === 200 && Tokres.body.access_token){
this.getKeycloakRoles(Tokres.body.access_token).subscribe((roleRes:any)=>{
console.log(roleRes);
},(roleErr:any)=>{
console.log('error while fetching roles..');
console.log(roleErr);
})
}
},(tokErr:any)=>{
console.log('error while accessing keycloak token...');
console.log(tokErr);
})
getKeycloakAccessToken(){
const url = 'http://keycloak-keycloak.router.default.svc.cluster.local.......nip.io/auth/realms/myRealm/protocol/openid-connect/token';
const authH = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
const body = new HttpParams()
.set('username', 'sample')
.set('password', 'sample')
.set('grant_type', 'password').set('client_id','rest-client');
return this.http.post(url, body,{headers:authH,observe:'response'});
}
getKeycloakRoles(access_token){
const url = 'http://keycloak-keycloak.router.default.svc.cluster.local........nip.io/auth/admin/realms/myRealm/roles'
const authH = new HttpHeaders().set('Authorization','Bearer ' + access_token);// ({'Authorization':'Bearer ' + access_token});
return this.http.get(url,{headers:authH,observe:'response'});
}
and when I tried to debug, the access_token shown in console is different from that of request headers
[![network log][2]][2]
After debugging for couple of days, I figured out the reason for the difference in Access token, the API call is being invoked with the access_token of logged in session, though the program has source code written to set the headers set with access token of user 'sample/sample'. is there any way to trigger the API with the given access_token rather with the logged in user's access_token.
This might not be the solution, but just a couple of workarounds that worked for me.
Allow permissions (set 'Relam Management') to all the logged in users from the key cloak admin console, this way irrespective of user, whoever logs in will be able access the rest Admin APIs, follow this below
reference
From keycloak client library, we have a initializeKeycloak() , that has configurations set for the application, so disable the 'enableBearerInterceptor' which will say the application not to use the access_token generated by logged in user to set the headers of each request. this way we can avoid the forbidden error.
But with approach no.2, you can not use the AT of logged in user as we r disabling the enableBearerInterceptor.
And with solution no.1, if you are not having control on who are the users logging in to your application, i,e using some third party tool like LDAP to set the users, then it this won't serve the solution.

Maintain flask_login session in flutter

Soo...I have an app with flask backend and flutter frontend. It utilizes flask_login to manage users. Problem is - I don't know how to maintain session on client side. Flutter client gets response from server, but I don't see any token, or user_id inside.
So far, I've tried to parse responce, with no luck and I've used solution from How do I make an http request using cookies on flutter?
also, without success.
Server-side https://github.com/GreenBlackSky/COIN/blob/master/api_app/app/login_bp.py
Client-side https://github.com/GreenBlackSky/coin_web_client/blob/master/lib/session.dart
Maybe, using flask_login was not such a good idea after all..
Have you tried with the request_loader approach? You can log in from Flutter client using a url argument and the Authorization header. Quoting from the documentation,
For example, to support login from both a url argument and from Basic Auth using the Authorization header:
#login_manager.request_loader
def load_user_from_request(request):
# first, try to login using the api_key url arg
api_key = request.args.get('api_key')
if api_key:
user = User.query.filter_by(api_key=api_key).first()
if user:
return user
# next, try to login using Basic Auth
api_key = request.headers.get('Authorization')
if api_key:
api_key = api_key.replace('Basic ', '', 1)
try:
api_key = base64.b64decode(api_key)
except TypeError:
pass
user = User.query.filter_by(api_key=api_key).first()
if user:
return user
# finally, return None if both methods did not login the user
return None
If you don't want to use flask_login anymore, I would suggest flask_jwt_extended for your case. Note that authentication will be carried out using JWT tokens instead of sessions.
Basically, you would need to create three routes: one for creating access and refresh tokens when the user logged in, one for refreshing the expired access token with the refresh token and one for removing the tokens when the user logged out. Then you would protect your API endpoints with the #jwt_required decorators.
Please refer to the documentation for detailed implementation.

Facebook .NET SDK -> Get and Post using generated token

I am writing a Azure Service that will occasionally write to my facebook page as a status. Since the service does not have a UI component, a majority of the examples on the Facebook and Facebook .NET SDK pages are not helpful.
I created an application on facebook and then fired up the F# REPL in Visual Studio. I generated the token like so:
#r "../packages/Facebook.7.0.6/lib/net45/Facebook.dll"
#r "../packages/Newtonsoft.Json.7.0.1/lib/net45/Newtonsoft.Json.dll"
open Facebook
open Newtonsoft.Json
type Credentials = {client_id:string; client_secret:string; grant_type:string;scope:string}
let credentials = {client_id="859968674039398";
client_secret="XXXXXXXXXX";
grant_type="client_credentials";
scope="manage_pages,publish_stream,read_stream,publish_checkins,offline_access"}
let client = FacebookClient()
let tokenJson = client.Get("oauth/access_token",credentials)
type Token = {access_token:string}
let token = JsonConvert.DeserializeObject<Token>(tokenJson.ToString())
A token comes back as expected. However, when I go to use the token, I am getting errors:
let client' = FacebookClient(token.access_token)
let me = client'.Get("me")
returns
An active access token must be used to query information about the
current user.
and
let pageId = "/me"
type FacecbookPost = {title:string; message:string}
let post = {title="Test Title"; message = "Test Message"}
let postResponse = client'.Post(pageId + "/feed", post)
returns
The user hasn't authorized the application to perform this action
When I read the docs, they talk about getting the application to be approved by Facebook -> but that makes no sense in my use case b/c there is no application as defined with a human end user -> or even any other user invoking the code.
When I generate the token on Facebook Graph Api explorer with the correct permissions, I can use the token to make those GETS and POSTS. Should I just generate the token and stick it in my .config file? How long does a token last?
Thanks in advance
I think you haven't fully understood how Facebook API works.
You always need an App to perform an action (in your case the APP is 859968674039398)
In order to post on behalf a user, you will need that user to grant permissions to your App.
Your App has to be public and if you require more permissions than the basic ones, you need to go through the review process.
The access token you get from the Graph API Explorer (which is an App BTW) is only for you.
Please read the docs CBro provided.
I hope it helps.

Access token error when trying to post a Facebook score in a canvas application

I'm trying to integrate the scoring system in my canvas app with Facebook's, implemented using MVC 3 and the 5.2.1.0 Facebook SDK.
A simplified hello-world variant of my game controller looks like:
public class MyController : Controller
{
[CanvasAuthorize("publish_action" /*And some others*/)]
public ActionResult Index()
{
var fb = new FacebookWebClient();
var scores = fb.Get("/me/scores"); // Works (I think)
fb.Post("/me/scores", new { score = 10 }); // Throws an exception
}
}
The call to get scores looks like it's giving me something sensible; the call to write a score value throws "(OAuthException) (#15) This method must be called with an app access_token."
What've I missed? The application id and secret are correctly set in my web.config - for example, I can successfully post an application apprequest in other parts of the actual application not shown in this stripped down test copy. Rummaging around with the debugger shows me that the FacebookWebClient object contains a non-empty access token field, and that that's included in the URI that fb.Post eventually uses.
The Facebook scores page (that Björn links to) mentions only publish_actions but I've tried including other pertinent sounding permissions, such as offline_access and user_games_activity to no effect.
I am assuming that the CanvasAuthorize attribute does the login correctly - it certainly seems to let me send an application apprequest, so it looks as if it's doing the right thing...
Your app needs the permission to write to the users profile. You can use the Graph API to request the required permissions from the user. If granted, Facebook will give you the required access token that you can then use in your request to Facebook. This practice ensures that you only perform actions, the user allowed you to.
Edit_: After looking at the docs: Are you sure you have the required permissions from the user like described here http://developers.facebook.com/docs/score/ ?
Please see this link. You'll need to get an facebook app. Using the apiId and SecretId, you can then post using the information in the link below. The key is adding &scope=manage_pages,offline_access,publish_stream to the url.
like so:
"https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials&scope=manage_pages,offline_access,publish_stream";

How do I write to someone's Facebook or Twitter wall using Omniauth?

I know Omniauth is just for authentication and it doesn't really have FB or Twitter tools included.
However, let's say my Rails 3 app uses Omniauth and I now have some users registered in my system.
How can I then post to their wall? Or do I need some other type of authorization system?
Thanks for any pointers.
I found this link which allowed me to post to both Facebook and Twitter. Very good tutorial:
http://blog.assimov.net/post/2358661274/twitter-integration-with-omniauth-and-devise-on-rails-3
I used this guide while setting up my application to connect to twitter:
http://philsturgeon.co.uk/news/2010/11/using-omniauth-to-make-twitteroauth-api-requests
Helped me a ton, hope it does for you the same.
Original post
Posted: Nov 16, 2010
Using the brilliant user system gem Devise and a gem called OmniAuth you can make a Rails application that logs in or registers users via Twitter, Facebook, Gowalla, etc with amazing ease. But once the user is logged in, how do you go about actually interacting with the API on behalf of the account that has just been authorized?
This article starts where RailsCasts leaves off, so if you are not already up and running with Devise and OmniAuth then you might want to watch:
RailsCast #209: Introducing Devise
RailsCast #235: OmniAuth Part 1
RailsCast #236: OmniAuth Part 2
So, assuming we are all about at the point that the third video ends on, we are all ready to go. I'll be using the example of Twitter but really any of the providers using oAuth will use the same approach. Like in the "ye-olden days" when we used the Twitter username and password to authenticate an API request, we now use a Access Token and Token Secret. You can think of these as being basically the same thing as for the purpose of authenticating API requests, to us, they are.
To get the token and secret you need to add some fields to your authentications table:
rails g migration AddTokenToAuthentications token:string secret:string
rake db:migrate
Now the database is ready to save the credentials we can change the authentication code to populate the fields. Assuming you placed the method in user.rb like RailsCast #236 suggested then open user.rb and modify the following line:
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
and replace it with:
authentications.build(
:provider => omniauth['provider'],
:uid => omniauth['uid'],
:token => omniauth['credentials']['token'],
:secret => omniauth['credentials']['secret']
)
Now whenever anybody authenticates their account we can save their credentials which are passed back from the internal hidden magic that is OmniAuth.
The next step is to actually make some requests using these saved credentials, which is described almost perfectly in the Twitter Developer Documentation. You'll want to install the oauth gem (put it in your Gemfile and run bundle install) then you can use the following code to test-dump a list of tweets from the user:
class TwitterController < ApplicationController
def recent_tweets
# Exchange your oauth_token and oauth_token_secret for an AccessToken instance.
def prepare_access_token(oauth_token, oauth_token_secret)
consumer = OAuth::Consumer.new("APIKey", "APISecret"
{ :site => "http://api.twitter.com"
})
# now create the access token object from passed values
token_hash = { :oauth_token => oauth_token,
:oauth_token_secret => oauth_token_secret
}
access_token = OAuth::AccessToken.from_hash(consumer, token_hash )
return access_token
end
auth = current_user.authentications.find(:first, :conditions => { :provider => 'twitter' })
# Exchange our oauth_token and oauth_token secret for the AccessToken instance.
access_token = prepare_access_token(auth['token'], auth['secret'])
# use the access token as an agent to get the home timeline
response = access_token.request(:get, "http://api.twitter.com/1/statuses/user_timeline.json")
render :json => response.body
end
end
By pulling the content from current_user.authentications (im finding the first as in my application they should only have one) I can grab the credentials and have full permissions to get their recent tweets, post new ones, see friends tweets, etc.
Now I can tweak this, get stuff saved, faff with the JSON and take what I need. Working with Facebook or any other oAuth provider will work in an almost identical way, or you can install specific gems to interact with their API's if the direct approach is not as smooth as you'd like.
end of original post