DRF JSON Token Authentication - authentication

I have to implement following features with RESTAPI:
register user
authorize user and get token
get user data by token
create user's post via token (Title, Body)
get user's posts via token
get all posts via token
user profile has to be customized - main fields are email/password
models.py:
http://pastebin.com/8V7CzrVi
serializers.py:
http://pastebin.com/W7Dn8Msn
views.py:
http://pastebin.com/L5ijkd5F
urls.py:
urlpatterns = [
url(r'^api/', include('app.urls')),
]
app.urls:
from .views import Register, UserList, UserDetail, PostList, PostDetail
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^users/$', UserList.as_view(), name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$', UserDetail.as_view(), name='user-detail'),
url(r'^posts/$', PostList.as_view(), name='post-list'),
url(r'^posts/(?P<pk>[0-9]+)/$', PostDetail.as_view(), name='post-detail'),
url(r'^login/', obtain_jwt_token),
url(r'^register/$', Register.as_view()),
]
First question - please, review the code and tell, am I right in my realization? (THANKS A LOT for any corrections, hints and explanations)
Second one - how can I perform creating the post or viewing of post's list without any client code?
I mean following:
I am going into browserable API at api/register, enter email and password, hit post and get object of user
then I am going at api/login, enter email and password of the user just registered, hit post and get object with token - {'token': 'sometoken'}
then I am trying to create the post or get post's list, using httpie. In the console I enter -
http POST 127.0.0.1:8000/api/posts "Authorization: Token sometoken"
or
http GET 127.0.0.1:8000/api/posts "Authorization: Token sometoken"
and get:
HTTP/1.0 301 MOVED PERMANENTLY
Content-Type: text/html; charset=utf-8
Date: Sat, 03 Sep 2016 10:22:33 GMT
Location: http://127.0.0.1:8000/api/posts/
Server: WSGIServer/0.1 Python/2.7.11
X-Frame-Options: SAMEORIGIN
I do not understand how I can check every endpoint with using token.
Thanks!!!

Related

Server-sent events in Rails not delivered asynchronously

I'm trying to write an API that delivers server-sent events using ActionController::Live::SSE in Rails 6. In order to understand how the tests would best be written, I started with essentially copying the trivial example seen here:
my_controller.rb:
class MyController < ApplicationController
include ActionController::Live
def capture
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream)
3.times do
sse.write({message: "Awaiting confirmation ..."})
sleep 2
end
fake_response = { #The response as hash.
"annotation_id"=>nil,
"domain"=>"some.random.com",
"id"=>2216354,
"path"=>"/flummoxer/",
"protocol"=>"https",
}
sse.write(fake_response, event: 'successful capture')
rescue => e
sse.write(e.message, event: 'something broke: ')
ensure
response.stream.close
end
end
When I send a curl request (whether I make it POST or GET) to this endpoint the response arrives all in one chunk, rather than as separate responses:
$ curl -i -X GET -H "Content-Type: application/json" -d '{"url": "https://some.random.com/flummoxer"}' http://localhost:3000/capture
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
ETag: W/"a24048695d2feca40232467f0fbb410a"
X-Request-Id: 648a5229-a43d-40d3-82fd-1c4ea6fe19cc
X-Runtime: 24.082528
Transfer-Encoding: chunked
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
This can more easily be seen by the fact that in my test, attempting to parse the response from my server fails:
MultiJson::ParseError: 783: unexpected token at 'data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
data: {"message":"Awaiting confirmation ..."}
event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
'
My server is Puma, so it's not because I'm using Thin, as seen in this answer.
What am I doing wrong? I'll provide any additional information that might be of use, if you ask.
UPDATE: The answers to this question suggest adding both the -N and the Accept:text/event-stream header to the request. Doing so doesn't change the behavior I've described above -- the response to the request isn't sent until the call to response.stream.close is fired.
UPDATE 2: I've also tried hacking the SSE#write method to call broadcast() on the Mutex::ConditionVariable to force sending the message. This works, in the sense that it sends data immediately, but has the side effect of the curl request thinking that the stream is closed, and so no further messages are sent, which is not a stream.
UPDATE 3: I've also modified development.rb to include config.allow_concurrency = true, as seen here. There's no change in the behavior described above.
I ran into a similar issue with a basic 'out the book' Rails 5 SSE app. The issue turned out to be a Rack update that lead to buffering of the stream. More info here https://github.com/rack/rack/issues/1619 and fixed by including
config.middleware.delete Rack::ETag
in config/application.rb

Get new access token with Authorization Code OAuth2 - Using Robot framework

I have some troubles with getting Access token with grant type authorization code using Robot framework with Oauth2.
We use also a username/password authentication and after give the following parameters we get back our access token:
Grant Type, Callback URL, Auth URL, Access Token URL, Client ID, Client Secret, Scope, State.
I tried with RequestsLibrary and ExtendedRequestsLibrary as well, but no success so far.
Actually I do not know how to add parameters: callback url, auth url, access token url and state.
First try - using RequestsLibrary
Get admin token
&{HEADER_TOKEN}= Create Dictionary Content-Type=${CONTENT_TYPE}
&{DATA_TOKEN}= Create Dictionary token_name=backend_token grant_type=${GRANT_TYPE} redirect_uri =${CALLBACK_URL} auth_url=${AUTH_URL} access_token_url=${ACCESS_TOKEN_URL} client_id=${CLIENT_ID} client_secret=${CLIENT_SECRET} scope=${SCOPE} state=${STATE} username=${USERNAME} ${PASSWORD}
${BACKEND_RESPONSE}= RequestsLibrary.Post Request ${BACKEND_SESSION} /oauth/token data=${DATA_TOKEN} headers=${HEADER_TOKEN}
Log to console ${BACKEND_RESPONSE}
Should Be Equal As Strings ${BACKEND_RESPONSE.status_code} 200
Second try - using ExtendedRequestsLibrary
Get brand new admin token
${SESSION_RESPONSE}= Create Password Oauth2 Session client ${TOKEN_URL} ${CLIENT_ID} ${CLIENT_SECRET} ${USERNAME} ${PASSWORD} base_url=${BASE_URL}
&{HEADER_TOKEN}= Create Dictionary Content-Type=${CONTENT_TYPE}
&{DATA_TOKEN}= Create Dictionary token_name=client grant_type=${GRANT_TYPE} callback_url=${CALLBACK_URL} auth_url=${AUTH_URL} access_token_url=${ACCESS_TOKEN_URL} client_id=${CLIENT_ID} client_secret=${CLIENT_SECRET} scope=${SCOPE} state=${STATE}
${BACKEND_RESPONSE}= ExtendedRequestsLibrary.Post Request client /oauth/token data=${DATA_TOKEN} headers=${HEADER_TOKEN}
Log to console ${BACKEND_RESPONSE}
Should Be Equal As Strings ${BACKEND_RESPONSE.status_code} 200
Log to console ${BACKEND_RESPONSE.status_code}
If you have any idea just let me know.
thx!
using RequestsLibrary try with this approach it should work:-
Create Session baseUri https://xxxxxx.xx.xxx/xxx/xx verify=True
&{params}= Create Dictionary client_id=${client_id} client_secret=${client_secret} grant_type=${grant_type}
&{headers}= Create Dictionary Content-Type=application/json
${resp}= Post Request baseUri /oauth/token none none ${params} ${headers}
Log to Console ${resp.json()['access_token']}
Status Should Be 200 ${resp}
you are passing data=${DATA_TOKEN} as a body in your post request. You need to send it as query params. First parameter will be alias 2nd is uri 3rd is data 4th is Json and 5th is query params so in
Post Request baseUri /oauth/token none none ${params} ${headers}
you will find 3rd and 4th parameter as none. Hope this works

How to disable encoding while passing a form field in karate

I am using the following code for oauth.
Feature: Verify Generate Token Email api is up and running
Scenario: Verify Generate Token Email api
Given url 'demourl'
And header Content-Type = 'application/x-www-form-urlencoded; charset=utf-8'
And form field grant_type = 'password'
And form field client_id = 'democlientid'
And form field client_secret = 'democlientsecret'
And form field password = 'randompass123'
And form field username = 'hello#someone.com'
When method post
Then status 200
* print response
The username field is getting encoded which results in =>
grant_type=password&client_id=democlientid&client_secret=democlientsecret&password=randompass123&username=hello%40someone.com
The name is getting encoded as "hello%40someone.com" while being passed because of which the api call fails. How do I disable encoding so that "hello#someone.com" is passes.
Karate is doing the right thing, it is most likely you have mis-understood the issue - or you have a bug in your server: https://www.w3schools.com/Tags/ref_urlencode.asp
Anyway if you insist on NOT encoding, you have to provide the request body manually. Use this example as a reference: https://github.com/intuit/karate/commit/58eeec344eb6b4194a7d5aa9bc5b2f0e934372ed

Telegram Bot API: getChatMember throws USER_ID_INVALID for valid user

I'm trying to find out if a specific User is present in a supergroup, in order to keep track of those who left.
For that, I'm calling the Bot API method getChatMember for each User and checking if their status is either Left or Kicked. However, I noticed that (recently?) I'm getting USER_ID_INVALID errors for many valid users that are either in the supergroup or have been in the past and then left. I also confirmed that those accounts are still active on Telegram.
Here's the HTTP request I'm sending:
POST https://api.telegram.org/botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXX/getChatMember HTTP/1.1
Connection: Keep-Alive
Content-Type: application/json; charset=utf-8
Content-Length: 46
Host: api.telegram.org
{"chat_id":-0000000000000,"user_id":000000000}
And here's the response I'm getting:
HTTP/1.1 400 Bad Request
Server: nginx/1.12.2
Date: Fri, 20 Apr 2018 04:17:32 GMT
Content-Type: application/json
Content-Length: 74
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length,Content-Type,Date,Server,Connection
{"ok":false,"error_code":400,"description":"Bad Request: USER_ID_INVALID"}
Any way I look at it, it looks like a perfectly valid request to me. And I haven't been able to find a common pattern between the users that throw this error.
What am I missing here?
EDIT: As #sean pointed out, having one of those users message the bot privately fixed the error for that particular user. But I'm absolutely sure that user was seen before because that's how I got his user ID. What could have caused the bot "forget" about him and how would I prevent this from happening in the future?
This error means your bot haven't seen this user before.
For instance, my user ID is 109780439, you can try getChatMember with #PublicTestGroup, it should response with 400 error.
And then, forward ANY of my message (e.g., this) to your bot, you will see the different result :)
You will create a variable who get your channel's result, like this:
$join : api.telegram.org/botYOURTOKEN/getchat .....
if($message && (strpos($join,'"status":"left"') or strpos($join,'"Bad Request: USER_ID_INVALID"') or strpos($join,'"status":"kicked"'))!== false) {
}

Getting response as 'Unauthorized' while sending access token via URI Query Parameter

We are creating REST API and implemented oAuth 2, using YII framework.
We are facing a strange issue, while we are trying to access the resource and sending access token via "Authorization Request Header Field" we are getting the expected output.
e.g.
curl -i -H "Accept:application/json" -H "Authorization: Bearer XXXXXX"
Whereas while we are trying to send the access token via "URI Query Parameter" we are getting response as "Unauthorized".
e.g.
https://server.example.com/resource?access_token=XXXXXX&p=q
Your suggestions would be really helpful for us.
RFC 6750 (Bearer Token Usage) defines 3 ways to pass an access token to a protected resource endpoint.
Via Authorization header. (2.1. Authorization Request Header Field)
Via a form parameter access_token. (2.2. Form-Encoded Body Parameter)
Via a query parameter access_token. (2.3. URI Query Parameter)
Among the above, only the first way is mandatory. It seems your authorization server does not support the third way.
Addition for the comment
Below is an example to support all the 3 ways in PHP. See "3. Extract Access Token" in "Protected Resource" for details and for other examples in Ruby and Java.
/**
* Function to extract an access token from a request.
*/
function extract_access_token()
{
// The value of Authorization header.
$header = $_SERVER['HTTP_AUTHORIZATION'];
// If the value is in the format of 'Bearer access-token'.
if ($header != null && preg_match('/^Bearer[ ]+(.+)/i', $header, $captured))
{
// Return the value extracted from Authorization header.
return $captured;
}
if ($_SERVER['REQUEST_METHOD'] == 'GET')
{
// Return the value of 'access_token' query parameter.
return $_GET['access_token'];
}
else
{
// Return the value of 'access_token' form parameter.
return $_POST['access_token'];
}
}
I don't know Yii, but my guess is that simply the framework does not contain code like the above.