mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-30 10:58:31 -05:00
Revert "Revert "BUGFIX: improve error messages for invalid API keys""
This reverts commit e9afe28586
.
This commit is contained in:
parent
43bac5467a
commit
cf254000cf
6 changed files with 94 additions and 40 deletions
|
@ -2,9 +2,11 @@ require_dependency "auth/current_user_provider"
|
||||||
|
|
||||||
class Auth::DefaultCurrentUserProvider
|
class Auth::DefaultCurrentUserProvider
|
||||||
|
|
||||||
CURRENT_USER_KEY ||= "_DISCOURSE_CURRENT_USER"
|
CURRENT_USER_KEY ||= "_DISCOURSE_CURRENT_USER".freeze
|
||||||
API_KEY ||= "_DISCOURSE_API"
|
API_KEY ||= "api_key".freeze
|
||||||
TOKEN_COOKIE ||= "_t"
|
API_KEY_ENV ||= "_DISCOURSE_API".freeze
|
||||||
|
TOKEN_COOKIE ||= "_t".freeze
|
||||||
|
PATH_INFO ||= "PATH_INFO".freeze
|
||||||
|
|
||||||
# do all current user initialization here
|
# do all current user initialization here
|
||||||
def initialize(env)
|
def initialize(env)
|
||||||
|
@ -12,12 +14,11 @@ class Auth::DefaultCurrentUserProvider
|
||||||
@request = Rack::Request.new(env)
|
@request = Rack::Request.new(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# our current user, return nil if none is found
|
# our current user, return nil if none is found
|
||||||
def current_user
|
def current_user
|
||||||
return @env[CURRENT_USER_KEY] if @env.key?(CURRENT_USER_KEY)
|
return @env[CURRENT_USER_KEY] if @env.key?(CURRENT_USER_KEY)
|
||||||
|
|
||||||
request = Rack::Request.new(@env)
|
request = @request
|
||||||
|
|
||||||
auth_token = request.cookies[TOKEN_COOKIE]
|
auth_token = request.cookies[TOKEN_COOKIE]
|
||||||
|
|
||||||
|
@ -31,33 +32,19 @@ class Auth::DefaultCurrentUserProvider
|
||||||
current_user = nil
|
current_user = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if current_user
|
if current_user && should_update_last_seen?
|
||||||
|
|
||||||
u = current_user
|
u = current_user
|
||||||
Scheduler::Defer.later do
|
Scheduler::Defer.later do
|
||||||
u.update_last_seen!
|
u.update_last_seen!
|
||||||
u.update_ip_address!(request.ip)
|
u.update_ip_address!(request.ip)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# possible we have an api call, impersonate
|
# possible we have an api call, impersonate
|
||||||
unless current_user
|
if api_key = request[API_KEY]
|
||||||
if api_key_value = request["api_key"]
|
current_user = lookup_api_user(api_key, request)
|
||||||
api_key = ApiKey.where(key: api_key_value).includes(:user).first
|
raise Discourse::InvalidAccess unless current_user
|
||||||
if api_key.present?
|
@env[API_KEY_ENV] = true
|
||||||
@env[API_KEY] = true
|
|
||||||
api_username = request["api_username"]
|
|
||||||
|
|
||||||
if api_key.user.present?
|
|
||||||
raise Discourse::InvalidAccess.new if api_username && (api_key.user.username_lower != api_username.downcase)
|
|
||||||
current_user = api_key.user
|
|
||||||
elsif api_username
|
|
||||||
current_user = User.find_by(username_lower: api_username.downcase)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@env[CURRENT_USER_KEY] = current_user
|
@env[CURRENT_USER_KEY] = current_user
|
||||||
|
@ -95,8 +82,28 @@ class Auth::DefaultCurrentUserProvider
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_auth_cookie?
|
def has_auth_cookie?
|
||||||
request = Rack::Request.new(@env)
|
cookie = @request.cookies[TOKEN_COOKIE]
|
||||||
cookie = request.cookies[TOKEN_COOKIE]
|
|
||||||
!cookie.nil? && cookie.length == 32
|
!cookie.nil? && cookie.length == 32
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def should_update_last_seen?
|
||||||
|
!(@request.path =~ /^\/message-bus\//)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def lookup_api_user(api_key_value, request)
|
||||||
|
api_key = ApiKey.where(key: api_key_value).includes(:user).first
|
||||||
|
if api_key
|
||||||
|
api_username = request["api_username"]
|
||||||
|
if api_key.user
|
||||||
|
api_key.user if !api_username || (api_key.user.username_lower == api_username.downcase)
|
||||||
|
elsif api_username
|
||||||
|
User.find_by(username_lower: api_username.downcase)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
50
spec/components/auth/default_current_user_provider_spec.rb
Normal file
50
spec/components/auth/default_current_user_provider_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require_dependency 'auth/default_current_user_provider'
|
||||||
|
|
||||||
|
describe Auth::DefaultCurrentUserProvider do
|
||||||
|
|
||||||
|
def provider(url, opts=nil)
|
||||||
|
opts ||= {method: "GET"}
|
||||||
|
env = Rack::MockRequest.env_for(url, opts)
|
||||||
|
Auth::DefaultCurrentUserProvider.new(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises errors for incorrect api_key" do
|
||||||
|
expect{
|
||||||
|
provider("/?api_key=INCORRECT").current_user
|
||||||
|
}.to raise_error(Discourse::InvalidAccess)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds a user for a correct per-user api key" do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
ApiKey.create!(key: "hello", user_id: user.id, created_by_id: -1)
|
||||||
|
provider("/?api_key=hello").current_user.id.should == user.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises for a user pretending" do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
user2 = Fabricate(:user)
|
||||||
|
ApiKey.create!(key: "hello", user_id: user.id, created_by_id: -1)
|
||||||
|
|
||||||
|
expect{
|
||||||
|
provider("/?api_key=hello&api_username=#{user2.username.downcase}").current_user
|
||||||
|
}.to raise_error(Discourse::InvalidAccess)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds a user for a correct system api key" do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
ApiKey.create!(key: "hello", created_by_id: -1)
|
||||||
|
provider("/?api_key=hello&api_username=#{user.username.downcase}").current_user.id.should == user.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not update last seen for message bus" do
|
||||||
|
provider("/message-bus/anything/goes", method: "POST").should_update_last_seen?.should == false
|
||||||
|
provider("/message-bus/anything/goes", method: "GET").should_update_last_seen?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should update last seen for others" do
|
||||||
|
provider("/topic/anything/goes", method: "POST").should_update_last_seen?.should == true
|
||||||
|
provider("/topic/anything/goes", method: "GET").should_update_last_seen?.should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -5,10 +5,9 @@ describe CurrentUser do
|
||||||
it "allows us to lookup a user from our environment" do
|
it "allows us to lookup a user from our environment" do
|
||||||
user = Fabricate(:user, auth_token: EmailToken.generate_token, active: true)
|
user = Fabricate(:user, auth_token: EmailToken.generate_token, active: true)
|
||||||
EmailToken.confirm(user.auth_token)
|
EmailToken.confirm(user.auth_token)
|
||||||
CurrentUser.lookup_from_env("HTTP_COOKIE" => "_t=#{user.auth_token};").should == user
|
|
||||||
|
env = Rack::MockRequest.env_for("/test", "HTTP_COOKIE" => "_t=#{user.auth_token};")
|
||||||
|
CurrentUser.lookup_from_env(env).should == user
|
||||||
end
|
end
|
||||||
|
|
||||||
# it "allows us to lookup a user from our app" do
|
|
||||||
# end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -163,16 +163,14 @@ describe 'api' do
|
||||||
|
|
||||||
it 'disallows phonies to bookmark posts' do
|
it 'disallows phonies to bookmark posts' do
|
||||||
PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never
|
PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never
|
||||||
lambda do
|
put :bookmark, bookmarked: "true", post_id: post.id, api_key: SecureRandom.hex(32), api_username: user.username, format: :json
|
||||||
put :bookmark, bookmarked: "true", post_id: post.id, api_key: SecureRandom.hex(32), api_username: user.username, format: :json
|
response.code.to_i.should == 403
|
||||||
end.should raise_error Discourse::NotLoggedIn
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'disallows blank api' do
|
it 'disallows blank api' do
|
||||||
PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never
|
PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never
|
||||||
lambda do
|
put :bookmark, bookmarked: "true", post_id: post.id, api_key: "", api_username: user.username, format: :json
|
||||||
put :bookmark, bookmarked: "true", post_id: post.id, api_key: "", api_username: user.username, format: :json
|
response.code.to_i.should == 403
|
||||||
end.should raise_error Discourse::NotLoggedIn
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -638,7 +638,7 @@ describe TopicsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when 'login required' site setting has been enabled" do
|
context "when 'login required' site setting has been enabled" do
|
||||||
before { SiteSetting.stubs(:login_required?).returns(true) }
|
before { SiteSetting.login_required = true }
|
||||||
|
|
||||||
context 'and the user is logged in' do
|
context 'and the user is logged in' do
|
||||||
before { log_in(:coding_horror) }
|
before { log_in(:coding_horror) }
|
||||||
|
@ -662,9 +662,9 @@ describe TopicsController do
|
||||||
expect(response).to be_successful
|
expect(response).to be_successful
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects to the login page if invalid key is provided' do
|
it 'returns 403 for an invalid key' do
|
||||||
get :show, topic_id: topic.id, slug: topic.slug, api_key: "bad"
|
get :show, topic_id: topic.id, slug: topic.slug, api_key: "bad"
|
||||||
expect(response).to redirect_to login_path
|
expect(response.code.to_i).to be(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ describe UserBadgesController do
|
||||||
it 'grants badges from master api calls' do
|
it 'grants badges from master api calls' do
|
||||||
api_key = Fabricate(:api_key)
|
api_key = Fabricate(:api_key)
|
||||||
StaffActionLogger.any_instance.expects(:log_badge_grant).never
|
StaffActionLogger.any_instance.expects(:log_badge_grant).never
|
||||||
xhr :post, :create, badge_id: badge.id, username: user.username, api_key: api_key.key
|
xhr :post, :create, badge_id: badge.id, username: user.username, api_key: api_key.key, api_username: "system"
|
||||||
response.status.should == 200
|
response.status.should == 200
|
||||||
user_badge = UserBadge.find_by(user: user, badge: badge)
|
user_badge = UserBadge.find_by(user: user, badge: badge)
|
||||||
user_badge.should be_present
|
user_badge.should be_present
|
||||||
|
|
Loading…
Reference in a new issue