add api authentication

This commit is contained in:
albert
2013-03-20 15:43:17 -07:00
parent 05aaefdf48
commit 7470d189c3
5 changed files with 94 additions and 4 deletions

View File

@@ -5,12 +5,22 @@ class ApplicationController < ActionController::Base
after_filter :reset_current_user
before_filter :set_title
before_filter :set_started_at_session
before_filter :api_check
layout "default"
rescue_from User::PrivilegeError, :with => :access_denied
rescue_from Danbooru::Paginator::PaginationError, :with => :render_pagination_limit
protected
def api_check
if CurrentUser.is_anonymous? && request.format.to_s =~ /json|xml/
render :text => "401 Not Authorized\n", :layout => false, :status => 401
return false
end
return true
end
def rescue_exception(exception)
@exception = exception
@@ -53,7 +63,7 @@ protected
end
def set_current_user
session_loader = SessionLoader.new(session, cookies, request)
session_loader = SessionLoader.new(session, cookies, request, params)
session_loader.load
end

View File

@@ -1,10 +1,11 @@
class SessionLoader
attr_reader :session, :cookies, :request
attr_reader :session, :cookies, :request, :params
def initialize(session, cookies, request)
def initialize(session, cookies, request, params)
@session = session
@cookies = cookies
@request = request
@params = params
end
def load
@@ -12,8 +13,10 @@ class SessionLoader
load_session_user
elsif cookie_password_hash_valid?
load_cookie_user
else
load_session_for_api
end
if CurrentUser.user
CurrentUser.user.unban! if ban_expired?
else
@@ -26,6 +29,32 @@ class SessionLoader
private
def load_session_for_api
if request.authorization
authenticate_basic_auth
elsif params[:login].present? && params[:api_key].present?
authenticate_api_key(params[:login], params[:api_key])
elsif params[:login].present? && params[:password_hash].present?
authenticate_legacy_api_key(params[:login], params[:password_hash])
end
end
def authenticate_basic_auth
credentials = ::Base64.decode64(request.authorization.split(' ', 2).last || '')
login, api_key = credentials.split(/:/, 2)
authenticate_api_key(login, api_key)
end
def authenticate_api_key(name, api_key)
CurrentUser.user = User.authenticate_cookie_hash(name, api_key)
end
def authenticate_legacy_api_key(name, password_hash)
CurrentUser.user = User.authenticate_hash(name, password_hash)
end
def load_session_user
CurrentUser.user = User.find_by_id(session[:user_id])
CurrentUser.ip_addr = request.remote_ip

View File

@@ -96,5 +96,12 @@
<% end %>
</td>
</tr>
<% if CurrentUser.user.id == user.id %>
<tr>
<th>API Key</th>
<td><%= CurrentUser.user.bcrypt_cookie_password_hash %></td>
</tr>
<% end %>
</table>
</div>

View File

@@ -42,6 +42,8 @@ h1. Authentication
All API calls must be authenticated. You can pass in two parameters: login and api_key. For legacy users, password_hash using the old salted SHA1 hashed password is also supported. Your API key is equivalent to your bcrypted password hash, which is stored in your cookies as password_hash. You can discover your API key by visiting your user profile. Your API key is intended to be a secret so you should not publicly distribute it.
You can also authenticate via HTTP Basic Authentication using your user name and API key.
Basic members can make 3,000 requests an hour. Gold members can make 10,000 requests an hour. Platinum members can make 20,000 requests an hour.
h1. Posts

View File

@@ -14,6 +14,48 @@ class PostsControllerTest < ActionController::TestCase
CurrentUser.user = nil
CurrentUser.ip_addr = nil
end
context "for api calls" do
context "using http basic auth" do
should "succeed for password matches" do
@basic_auth_string = "Basic #{ActiveSupport::Base64.encode64("#{@user.name}:#{@user.bcrypt_cookie_password_hash}")}"
@request.env['HTTP_AUTHORIZATION'] = @basic_auth_string
get :index, {:format => "json"}
assert_response :success
end
should "fail for password mismatches" do
@basic_auth_string = "Basic #{ActiveSupport::Base64.encode64("#{@user.name}:badpassword")}"
@request.env['HTTP_AUTHORIZATION'] = @basic_auth_string
get :index, {:format => "json"}
assert_response 401
end
end
context "using the api_key parameter" do
should "succeed for password matches" do
get :index, {:format => "json", :login => @user.name, :api_key => @user.bcrypt_cookie_password_hash}
assert_response :success
end
should "fail for password mismatches" do
get :index, {:format => "json", :login => @user.name, :api_key => "bad"}
assert_response 401
end
end
context "using the password_hash parameter" do
should "succeed for password matches" do
get :index, {:format => "json", :login => @user.name, :password_hash => User.sha1("password")}
assert_response :success
end
should "fail for password mismatches" do
get :index, {:format => "json", :login => @user.name, :password_hash => "bad"}
assert_response 401
end
end
end
context "index action" do
should "render" do