doorkeeper-2.2.1/0000755000076400007640000000000012544753400012713 5ustar pravipravidoorkeeper-2.2.1/spec/0000755000076400007640000000000012544753400013645 5ustar pravipravidoorkeeper-2.2.1/spec/spec_helper.rb0000644000076400007640000000024212544753400016461 0ustar pravipravi$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../lib')) $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../app')) doorkeeper-2.2.1/spec/factories.rb0000644000076400007640000000116712544753400016156 0ustar pravipraviFactoryGirl.define do factory :access_grant, class: Doorkeeper::AccessGrant do sequence(:resource_owner_id) { |n| n } application redirect_uri 'https://app.com/callback' expires_in 100 scopes 'public write' end factory :access_token, class: Doorkeeper::AccessToken do sequence(:resource_owner_id) { |n| n } application expires_in 2.hours factory :clientless_access_token do application nil end end factory :application, class: Doorkeeper::Application do sequence(:name) { |n| "Application #{n}" } redirect_uri 'https://app.com/callback' end factory :user end doorkeeper-2.2.1/spec/routing/0000755000076400007640000000000012544753400015334 5ustar pravipravidoorkeeper-2.2.1/spec/routing/scoped_routes_spec.rb0000644000076400007640000000226212544753400021553 0ustar pravipravirequire 'spec_helper_integration' describe 'Scoped routes' do it 'GET /scope/authorize routes to authorizations controller' do expect(get('/scope/authorize')).to route_to('doorkeeper/authorizations#new') end it 'POST /scope/authorize routes to authorizations controller' do expect(post('/scope/authorize')).to route_to('doorkeeper/authorizations#create') end it 'DELETE /scope/authorize routes to authorizations controller' do expect(delete('/scope/authorize')).to route_to('doorkeeper/authorizations#destroy') end it 'POST /scope/token routes to tokens controller' do expect(post('/scope/token')).to route_to('doorkeeper/tokens#create') end it 'GET /scope/applications routes to applications controller' do expect(get('/scope/applications')).to route_to('doorkeeper/applications#index') end it 'GET /scope/authorized_applications routes to authorized applications controller' do expect(get('/scope/authorized_applications')).to route_to('doorkeeper/authorized_applications#index') end it 'GET /scope/token/info route to authorzed tokeninfo controller' do expect(get('/scope/token/info')).to route_to('doorkeeper/token_info#show') end end doorkeeper-2.2.1/spec/routing/custom_controller_routes_spec.rb0000644000076400007640000000544712544753400024063 0ustar pravipravirequire 'spec_helper_integration' describe 'Custom controller for routes' do it 'GET /space/scope/authorize routes to custom authorizations controller' do expect(get('/inner_space/scope/authorize')).to route_to('custom_authorizations#new') end it 'POST /space/scope/authorize routes to custom authorizations controller' do expect(post('/inner_space/scope/authorize')).to route_to('custom_authorizations#create') end it 'DELETE /space/scope/authorize routes to custom authorizations controller' do expect(delete('/inner_space/scope/authorize')).to route_to('custom_authorizations#destroy') end it 'POST /space/scope/token routes to tokens controller' do expect(post('/inner_space/scope/token')).to route_to('custom_authorizations#create') end it 'GET /space/scope/applications routes to applications controller' do expect(get('/inner_space/scope/applications')).to route_to('custom_authorizations#index') end it 'GET /space/scope/token/info routes to the token_info controller' do expect(get('/inner_space/scope/token/info')).to route_to('custom_authorizations#show') end it 'GET /space/oauth/authorize routes to custom authorizations controller' do expect(get('/space/oauth/authorize')).to route_to('custom_authorizations#new') end it 'POST /space/oauth/authorize routes to custom authorizations controller' do expect(post('/space/oauth/authorize')).to route_to('custom_authorizations#create') end it 'DELETE /space/oauth/authorize routes to custom authorizations controller' do expect(delete('/space/oauth/authorize')).to route_to('custom_authorizations#destroy') end it 'POST /space/oauth/token routes to tokens controller' do expect(post('/space/oauth/token')).to route_to('custom_authorizations#create') end it 'POST /space/oauth/revoke routes to tokens controller' do expect(post('/space/oauth/revoke')).to route_to('custom_authorizations#revoke') end it 'GET /space/oauth/applications routes to applications controller' do expect(get('/space/oauth/applications')).to route_to('custom_authorizations#index') end it 'GET /space/oauth/token/info routes to the token_info controller' do expect(get('/space/oauth/token/info')).to route_to('custom_authorizations#show') end it 'POST /outer_space/oauth/token is not be routable' do expect(post('/outer_space/oauth/token')).not_to be_routable end it 'GET /outer_space/oauth/authorize routes to custom authorizations controller' do expect(get('/outer_space/oauth/authorize')).to be_routable end it 'GET /outer_space/oauth/applications is not routable' do expect(get('/outer_space/oauth/applications')).not_to be_routable end it 'GET /outer_space/oauth/token_info is not routable' do expect(get('/outer_space/oauth/token/info')).not_to be_routable end end doorkeeper-2.2.1/spec/routing/default_routes_spec.rb0000644000076400007640000000247512544753400021730 0ustar pravipravirequire 'spec_helper_integration' describe 'Default routes' do it 'GET /oauth/authorize routes to authorizations controller' do expect(get('/oauth/authorize')).to route_to('doorkeeper/authorizations#new') end it 'POST /oauth/authorize routes to authorizations controller' do expect(post('/oauth/authorize')).to route_to('doorkeeper/authorizations#create') end it 'DELETE /oauth/authorize routes to authorizations controller' do expect(delete('/oauth/authorize')).to route_to('doorkeeper/authorizations#destroy') end it 'POST /oauth/token routes to tokens controller' do expect(post('/oauth/token')).to route_to('doorkeeper/tokens#create') end it 'POST /oauth/revoke routes to tokens controller' do expect(post('/oauth/revoke')).to route_to('doorkeeper/tokens#revoke') end it 'GET /oauth/applications routes to applications controller' do expect(get('/oauth/applications')).to route_to('doorkeeper/applications#index') end it 'GET /oauth/authorized_applications routes to authorized applications controller' do expect(get('/oauth/authorized_applications')).to route_to('doorkeeper/authorized_applications#index') end it 'GET /oauth/token/info route to authorzed tokeninfo controller' do expect(get('/oauth/token/info')).to route_to('doorkeeper/token_info#show') end end doorkeeper-2.2.1/spec/spec_helper_integration.rb0000644000076400007640000000330612544753400021070 0ustar pravipraviENV['RAILS_ENV'] ||= 'test' TABLE_NAME_PREFIX = ENV['table_name_prefix'] || nil TABLE_NAME_SUFFIX = ENV['table_name_suffix'] || nil orm = (ENV['BUNDLE_GEMFILE'] || '').match(/Gemfile\.(.+)\.rb/) DOORKEEPER_ORM = (orm && orm[1] || :active_record).to_sym $LOAD_PATH.unshift File.dirname(__FILE__) require 'capybara/rspec' require 'rspec/active_model/mocks' require 'dummy/config/environment' require 'rspec/rails' require 'generator_spec/test_case' require 'timecop' require 'database_cleaner' require 'pry' Rails.logger.info "====> Doorkeeper.orm = #{Doorkeeper.configuration.orm.inspect}" if Doorkeeper.configuration.orm == :active_record Rails.logger.info "======> active_record.table_name_prefix = #{Rails.configuration.active_record.table_name_prefix.inspect}" Rails.logger.info "======> active_record.table_name_suffix = #{Rails.configuration.active_record.table_name_suffix.inspect}" end Rails.logger.info "====> Rails version: #{Rails.version}" Rails.logger.info "====> Ruby version: #{RUBY_VERSION}" if [:mongoid2, :mongoid3, :mongoid4].include?(DOORKEEPER_ORM) require "support/orm/mongoid" else require "support/orm/#{DOORKEEPER_ORM}" end ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../') Dir["#{File.dirname(__FILE__)}/support/{dependencies,helpers,shared}/*.rb"].each { |f| require f } RSpec.configure do |config| config.infer_spec_type_from_file_location! config.mock_with :rspec config.infer_base_class_for_anonymous_controllers = false config.include RSpec::Rails::RequestExampleGroup, type: :request config.before do DatabaseCleaner.start Doorkeeper.configure { orm DOORKEEPER_ORM } end config.after do DatabaseCleaner.clean end config.order = 'random' end doorkeeper-2.2.1/spec/requests/0000755000076400007640000000000012544753400015520 5ustar pravipravidoorkeeper-2.2.1/spec/requests/applications/0000755000076400007640000000000012544753400020206 5ustar pravipravidoorkeeper-2.2.1/spec/requests/applications/authorized_applications_spec.rb0000644000076400007640000000172012544753400026471 0ustar pravipravirequire 'spec_helper_integration' feature 'Authorized applications' do background do @user = User.create!(name: 'Joe', password: 'sekret') @client = client_exists(name: 'Amazing Client App') resource_owner_is_authenticated @user client_is_authorized @client, @user end scenario 'display user\'s authorized applications' do visit '/oauth/authorized_applications' i_should_see 'Amazing Client App' end scenario 'do not display other user\'s authorized applications' do client = client_exists(name: 'Another Client App') client_is_authorized client, User.create!(name: 'Joe', password: 'sekret') visit '/oauth/authorized_applications' i_should_not_see 'Another Client App' end scenario 'user revoke access to application' do visit '/oauth/authorized_applications' i_should_see 'Amazing Client App' click_on 'Revoke' i_should_see 'Application revoked' i_should_not_see 'Amazing Client App' end end doorkeeper-2.2.1/spec/requests/applications/applications_request_spec.rb0000644000076400007640000000445212544753400026010 0ustar pravipravirequire 'spec_helper_integration' feature 'Adding applications' do context 'in application form' do background do visit '/oauth/applications/new' end scenario 'adding a valid app' do fill_in 'doorkeeper_application[name]', with: 'My Application' fill_in 'doorkeeper_application[redirect_uri]', with: 'https://example.com' click_button 'Submit' i_should_see 'Application created' i_should_see 'My Application' end scenario 'adding invalid app' do click_button 'Submit' i_should_see 'Whoops! Check your form for possible errors' end end end feature 'Listing applications' do background do FactoryGirl.create :application, name: 'Oauth Dude' FactoryGirl.create :application, name: 'Awesome App' end scenario 'application list' do visit '/oauth/applications' i_should_see 'Awesome App' i_should_see 'Oauth Dude' end end feature 'Show application' do given :app do FactoryGirl.create :application, name: 'Just another oauth app' end scenario 'visiting application page' do visit "/oauth/applications/#{app.id}" i_should_see 'Just another oauth app' end end feature 'Edit application' do let :app do FactoryGirl.create :application, name: 'OMG my app' end background do visit "/oauth/applications/#{app.id}/edit" end scenario 'updating a valid app' do fill_in 'doorkeeper_application[name]', with: 'Serious app' click_button 'Submit' i_should_see 'Application updated' i_should_see 'Serious app' i_should_not_see 'OMG my app' end scenario 'updating an invalid app' do fill_in 'doorkeeper_application[name]', with: '' click_button 'Submit' i_should_see 'Whoops! Check your form for possible errors' end end feature 'Remove application' do background do @app = FactoryGirl.create :application end scenario 'deleting an application from list' do visit '/oauth/applications' i_should_see @app.name within(:css, "tr#application_#{@app.id}") do click_button 'Destroy' end i_should_see 'Application deleted' i_should_not_see @app.name end scenario 'deleting an application from show' do visit "/oauth/applications/#{@app.id}" click_button 'Destroy' i_should_see 'Application deleted' end end doorkeeper-2.2.1/spec/requests/flows/0000755000076400007640000000000012544753400016652 5ustar pravipravidoorkeeper-2.2.1/spec/requests/flows/implicit_grant_spec.rb0000644000076400007640000000342212544753400023217 0ustar pravipravirequire 'spec_helper_integration' feature 'Implicit Grant Flow (feature spec)' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } config_is_set(:grant_flows, ["implicit"]) client_exists create_resource_owner sign_in end scenario 'resource owner authorizes the client' do visit authorization_endpoint_url(client: @client, response_type: 'token') click_on 'Authorize' access_token_should_exist_for @client, @resource_owner i_should_be_on_client_callback @client end end describe 'Implicit Grant Flow (request spec)' do before do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } config_is_set(:grant_flows, ["implicit"]) client_exists create_resource_owner end context 'token reuse' do it 'should return a new token each request' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(false) token = client_is_authorized(@client, @resource_owner) post "/oauth/authorize", client_id: @client.uid, state: '', redirect_uri: @client.redirect_uri, response_type: 'token', commit: 'Authorize' expect(response.location).not_to include(token.token) end it 'should return the same token if it is still accessible' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) token = client_is_authorized(@client, @resource_owner) post "/oauth/authorize", client_id: @client.uid, state: '', redirect_uri: @client.redirect_uri, response_type: 'token', commit: 'Authorize' expect(response.location).to include(token.token) end end end doorkeeper-2.2.1/spec/requests/flows/authorization_code_errors_spec.rb0000644000076400007640000000376712544753400025514 0ustar pravipravirequire 'spec_helper_integration' feature 'Authorization Code Flow Errors' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } client_exists create_resource_owner sign_in end after do access_grant_should_not_exist end context 'when access was denied' do scenario 'redirects with error' do visit authorization_endpoint_url(client: @client) click_on 'Deny' i_should_be_on_client_callback @client url_should_not_have_param 'code' url_should_have_param 'error', 'access_denied' url_should_have_param 'error_description', translated_error_message(:access_denied) end scenario 'redirects with state parameter' do visit authorization_endpoint_url(client: @client, state: 'return-this') click_on 'Deny' i_should_be_on_client_callback @client url_should_not_have_param 'code' url_should_have_param 'state', 'return-this' end end end describe 'Authorization Code Flow Errors', 'after authorization' do before do client_exists authorization_code_exists application: @client end it 'returns :invalid_grant error when posting an already revoked grant code' do # First successful request post token_endpoint_url(code: @authorization.token, client: @client) # Second attempt with same token expect do post token_endpoint_url(code: @authorization.token, client: @client) end.to_not change { Doorkeeper::AccessToken.count } should_not_have_json 'access_token' should_have_json 'error', 'invalid_grant' should_have_json 'error_description', translated_error_message('invalid_grant') end it 'returns :invalid_grant error for invalid grant code' do post token_endpoint_url(code: 'invalid', client: @client) access_token_should_not_exist should_not_have_json 'access_token' should_have_json 'error', 'invalid_grant' should_have_json 'error_description', translated_error_message('invalid_grant') end end doorkeeper-2.2.1/spec/requests/flows/skip_authorization_spec.rb0000644000076400007640000000431412544753400024141 0ustar pravipravirequire 'spec_helper_integration' feature 'Skip authorization form' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } client_exists default_scopes_exist :public optional_scopes_exist :write end context 'for previously authorized clients' do background do create_resource_owner sign_in end scenario 'skips the authorization and return a new grant code' do client_is_authorized(@client, @resource_owner, scopes: 'public') visit authorization_endpoint_url(client: @client) i_should_not_see 'Authorize' client_should_be_authorized @client i_should_be_on_client_callback @client url_should_have_param 'code', Doorkeeper::AccessGrant.first.token end scenario 'does not skip authorization when scopes differ (new request has fewer scopes)' do client_is_authorized(@client, @resource_owner, scopes: 'public write') visit authorization_endpoint_url(client: @client, scope: 'public') i_should_see 'Authorize' end scenario 'does not skip authorization when scopes differ (new request has more scopes)' do client_is_authorized(@client, @resource_owner, scopes: 'public write') visit authorization_endpoint_url(client: @client, scopes: 'public write email') i_should_see 'Authorize' end scenario 'creates grant with new scope when scopes differ' do client_is_authorized(@client, @resource_owner, scopes: 'public write') visit authorization_endpoint_url(client: @client, scope: 'public') click_on 'Authorize' access_grant_should_have_scopes :public end scenario 'doesn not skip authorization when scopes are greater' do client_is_authorized(@client, @resource_owner, scopes: 'public') visit authorization_endpoint_url(client: @client, scope: 'public write') i_should_see 'Authorize' end scenario 'creates grant with new scope when scopes are greater' do client_is_authorized(@client, @resource_owner, scopes: 'public') visit authorization_endpoint_url(client: @client, scope: 'public write') click_on 'Authorize' access_grant_should_have_scopes :public, :write end end end doorkeeper-2.2.1/spec/requests/flows/authorization_code_spec.rb0000644000076400007640000001101112544753400024075 0ustar pravipravirequire 'spec_helper_integration' feature 'Authorization Code Flow' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } client_exists create_resource_owner sign_in end scenario 'resource owner authorizes the client' do visit authorization_endpoint_url(client: @client) click_on 'Authorize' access_grant_should_exist_for(@client, @resource_owner) i_should_be_on_client_callback(@client) url_should_have_param('code', Doorkeeper::AccessGrant.first.token) url_should_not_have_param('state') url_should_not_have_param('error') end scenario 'resource owner authorizes using test url' do @client.redirect_uri = Doorkeeper.configuration.native_redirect_uri @client.save! visit authorization_endpoint_url(client: @client) click_on 'Authorize' access_grant_should_exist_for(@client, @resource_owner) i_should_see 'Authorization code:' i_should_see Doorkeeper::AccessGrant.first.token end scenario 'resource owner authorizes the client with state parameter set' do visit authorization_endpoint_url(client: @client, state: 'return-me') click_on 'Authorize' url_should_have_param('code', Doorkeeper::AccessGrant.first.token) url_should_have_param('state', 'return-me') end scenario 'resource owner requests an access token with authorization code' do skip 'TODO: need to add request helpers to this feature spec' visit authorization_endpoint_url(client: @client) click_on 'Authorize' authorization_code = Doorkeeper::AccessGrant.first.token post token_endpoint_url(code: authorization_code, client: @client) access_token_should_exist_for(@client, @resource_owner) should_not_have_json 'error' should_have_json 'access_token', Doorkeeper::AccessToken.first.token should_have_json 'token_type', 'bearer' should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1 end context 'with scopes' do background do default_scopes_exist :public optional_scopes_exist :write end scenario 'resource owner authorizes the client with default scopes' do visit authorization_endpoint_url(client: @client) click_on 'Authorize' access_grant_should_exist_for(@client, @resource_owner) access_grant_should_have_scopes :public end scenario 'resource owner authorizes the client with required scopes' do visit authorization_endpoint_url(client: @client, scope: 'public write') click_on 'Authorize' access_grant_should_have_scopes :public, :write end scenario 'resource owner authorizes the client with required scopes (without defaults)' do visit authorization_endpoint_url(client: @client, scope: 'write') click_on 'Authorize' access_grant_should_have_scopes :write end scenario 'new access token matches required scopes' do skip 'TODO: need to add request helpers to this feature spec' visit authorization_endpoint_url(client: @client, scope: 'public write') click_on 'Authorize' authorization_code = Doorkeeper::AccessGrant.first.token post token_endpoint_url(code: authorization_code, client: @client) access_token_should_exist_for(@client, @resource_owner) access_token_should_have_scopes :public, :write end scenario 'returns new token if scopes have changed' do skip 'TODO: need to add request helpers to this feature spec' client_is_authorized(@client, @resource_owner, scopes: 'public write') visit authorization_endpoint_url(client: @client, scope: 'public') click_on 'Authorize' authorization_code = Doorkeeper::AccessGrant.first.token post token_endpoint_url(code: authorization_code, client: @client) expect(Doorkeeper::AccessToken.count).to be(2) should_have_json 'access_token', Doorkeeper::AccessToken.last.token end scenario 'resource owner authorizes the client with extra scopes' do skip 'TODO: need to add request helpers to this feature spec' client_is_authorized(@client, @resource_owner, scopes: 'public') visit authorization_endpoint_url(client: @client, scope: 'public write') click_on 'Authorize' authorization_code = Doorkeeper::AccessGrant.first.token post token_endpoint_url(code: authorization_code, client: @client) expect(Doorkeeper::AccessToken.count).to be(2) should_have_json 'access_token', Doorkeeper::AccessToken.last.token access_token_should_have_scopes :public, :write end end end doorkeeper-2.2.1/spec/requests/flows/refresh_token_spec.rb0000644000076400007640000000663512544753400023061 0ustar pravipravirequire 'spec_helper_integration' describe 'Refresh Token Flow' do before do Doorkeeper.configure do orm DOORKEEPER_ORM use_refresh_token end client_exists end context 'issuing a refresh token' do before do authorization_code_exists application: @client end it 'client gets the refresh token and refreshses it' do post token_endpoint_url(code: @authorization.token, client: @client) token = Doorkeeper::AccessToken.first should_have_json 'access_token', token.token should_have_json 'refresh_token', token.refresh_token expect(@authorization.reload).to be_revoked post refresh_token_endpoint_url(client: @client, refresh_token: token.refresh_token) new_token = Doorkeeper::AccessToken.last should_have_json 'access_token', new_token.token should_have_json 'refresh_token', new_token.refresh_token expect(token.token).not_to eq(new_token.token) expect(token.refresh_token).not_to eq(new_token.refresh_token) end end context 'refreshing the token' do before do @token = FactoryGirl.create(:access_token, application: @client, resource_owner_id: 1, use_refresh_token: true) end it 'client request a token with refresh token' do post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token) should_have_json 'refresh_token', Doorkeeper::AccessToken.last.refresh_token expect(@token.reload).to be_revoked end it 'client request a token with expired access token' do @token.update_attribute :expires_in, -100 post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token) should_have_json 'refresh_token', Doorkeeper::AccessToken.last.refresh_token expect(@token.reload).to be_revoked end it 'client gets an error for invalid refresh token' do post refresh_token_endpoint_url(client: @client, refresh_token: 'invalid') should_not_have_json 'refresh_token' should_have_json 'error', 'invalid_grant' end it 'client gets an error for revoked acccess token' do @token.revoke post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token) should_not_have_json 'refresh_token' should_have_json 'error', 'invalid_grant' end end context 'refreshing the token with multiple sessions (devices)' do before do # enable password auth to simulate other devices config_is_set(:grant_flows, ["password"]) config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] } create_resource_owner _another_token = post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) last_token.update_attribute :created_at, 5.seconds.ago @token = FactoryGirl.create(:access_token, application: @client, resource_owner_id: @resource_owner.id, use_refresh_token: true) @token.update_attribute :expires_in, -100 end it 'client request a token after creating another token with the same user' do post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token) should_have_json 'refresh_token', last_token.refresh_token expect(@token.reload).to be_revoked end def last_token Doorkeeper::AccessToken.last_authorized_token_for( @client.id, @resource_owner.id ) end end end doorkeeper-2.2.1/spec/requests/flows/implicit_grant_errors_spec.rb0000644000076400007640000000202512544753400024611 0ustar pravipravirequire 'spec_helper_integration' feature 'Implicit Grant Flow Errors' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } config_is_set(:grant_flows, ["implicit"]) client_exists create_resource_owner sign_in end after do access_token_should_not_exist end [ [:client_id, :invalid_client], [:redirect_uri, :invalid_redirect_uri] ].each do |error| scenario "displays #{error.last.inspect} error for invalid #{error.first.inspect}" do visit authorization_endpoint_url(client: @client, error.first => 'invalid', response_type: 'token') i_should_not_see 'Authorize' i_should_see_translated_error_message error.last end scenario "displays #{error.last.inspect} error when #{error.first.inspect} is missing" do visit authorization_endpoint_url(client: @client, error.first => '', response_type: 'token') i_should_not_see 'Authorize' i_should_see_translated_error_message error.last end end end doorkeeper-2.2.1/spec/requests/flows/password_spec.rb0000644000076400007640000000613012544753400022053 0ustar pravipravirequire 'spec_helper_integration' describe 'Resource Owner Password Credentials Flow not set up' do before do client_exists create_resource_owner end context 'with valid user credentials' do it 'doesn\'t issue new token' do expect do post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) end.to_not change { Doorkeeper::AccessToken.count } end end end describe 'Resource Owner Password Credentials Flow' do before do config_is_set(:grant_flows, ["password"]) config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] } client_exists create_resource_owner end context 'with valid user credentials' do it 'should issue new token' do expect do post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) end.to change { Doorkeeper::AccessToken.count }.by(1) token = Doorkeeper::AccessToken.first should_have_json 'access_token', token.token end it 'should issue new token without client credentials' do expect do post password_token_endpoint_url(resource_owner: @resource_owner) end.to change { Doorkeeper::AccessToken.count }.by(1) token = Doorkeeper::AccessToken.first should_have_json 'access_token', token.token end it 'should issue a refresh token if enabled' do config_is_set(:refresh_token_enabled, true) post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) token = Doorkeeper::AccessToken.first should_have_json 'refresh_token', token.refresh_token end it 'should return the same token if it is still accessible' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) client_is_authorized(@client, @resource_owner) post password_token_endpoint_url(client: @client, resource_owner: @resource_owner) expect(Doorkeeper::AccessToken.count).to be(1) should_have_json 'access_token', Doorkeeper::AccessToken.first.token end end context 'with invalid user credentials' do it 'should not issue new token with bad password' do expect do post password_token_endpoint_url(client: @client, resource_owner_username: @resource_owner.name, resource_owner_password: 'wrongpassword') end.to_not change { Doorkeeper::AccessToken.count } end it 'should not issue new token without credentials' do expect do post password_token_endpoint_url(client: @client) end.to_not change { Doorkeeper::AccessToken.count } end end context 'with invalid client credentials' do it 'should not issue new token with bad client credentials' do expect do post password_token_endpoint_url(client_id: @client.uid, client_secret: 'bad_secret', resource_owner: @resource_owner) end.to_not change { Doorkeeper::AccessToken.count } end end end doorkeeper-2.2.1/spec/requests/flows/revoke_token_spec.rb0000644000076400007640000001357312544753400022715 0ustar pravipravirequire 'spec_helper_integration' describe 'Revoke Token Flow' do before do Doorkeeper.configure { orm DOORKEEPER_ORM } end context 'with default parameters' do let(:client_application) { FactoryGirl.create :application } let(:resource_owner) { User.create!(name: 'John', password: 'sekret') } let(:authorization_access_token) do FactoryGirl.create(:access_token, application: client_application, resource_owner_id: resource_owner.id, use_refresh_token: true) end let(:headers) { { 'HTTP_AUTHORIZATION' => "Bearer #{authorization_access_token.token}" } } context 'With invalid token to revoke' do it 'client wants to revoke the given access token' do post revocation_token_endpoint_url, { token: 'I_AM_AN_INVALIDE_TOKEN' }, headers authorization_access_token.reload # The authorization server responds with HTTP status code 200 if the token # has been revoked successfully or if the client submitted an invalid token. expect(response).to be_success expect(authorization_access_token).to_not be_revoked end end context 'The access token to revoke is the same than the authorization access token' do let(:token_to_revoke) { authorization_access_token } it 'client wants to revoke the given access token' do post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers token_to_revoke.reload authorization_access_token.reload expect(response).to be_success expect(token_to_revoke.revoked?).to be_truthy expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy end it 'client wants to revoke the given access token using the POST query string' do url_with_query_string = revocation_token_endpoint_url + '?' + Rack::Utils.build_query(token: token_to_revoke.token) post url_with_query_string, {}, headers token_to_revoke.reload authorization_access_token.reload expect(response).to be_success expect(token_to_revoke.revoked?).to be_falsey expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey expect(authorization_access_token.revoked?).to be_falsey end end context 'The access token to revoke app and owners are the same than the authorization access token' do let(:token_to_revoke) do FactoryGirl.create(:access_token, application: client_application, resource_owner_id: resource_owner.id, use_refresh_token: true) end it 'client wants to revoke the given access token' do post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers token_to_revoke.reload authorization_access_token.reload expect(response).to be_success expect(token_to_revoke.revoked?).to be_truthy expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy expect(authorization_access_token.revoked?).to be_falsey end end context 'The access token to revoke authorization owner is the same than the authorization access token' do let(:other_client_application) { FactoryGirl.create :application } let(:token_to_revoke) do FactoryGirl.create(:access_token, application: other_client_application, resource_owner_id: resource_owner.id, use_refresh_token: true) end it 'client wants to revoke the given access token' do post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers token_to_revoke.reload authorization_access_token.reload expect(response).to be_success expect(token_to_revoke.revoked?).to be_falsey expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey expect(authorization_access_token.revoked?).to be_falsey end end context 'The access token to revoke app is the same than the authorization access token' do let(:other_resource_owner) { User.create!(name: 'Matheo', password: 'pareto') } let(:token_to_revoke) do FactoryGirl.create(:access_token, application: client_application, resource_owner_id: other_resource_owner.id, use_refresh_token: true) end it 'client wants to revoke the given access token' do post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers token_to_revoke.reload authorization_access_token.reload expect(response).to be_success expect(token_to_revoke.revoked?).to be_falsey expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey expect(authorization_access_token.revoked?).to be_falsey end end context 'With valid refresh token to revoke' do let(:token_to_revoke) do FactoryGirl.create(:access_token, application: client_application, resource_owner_id: resource_owner.id, use_refresh_token: true) end it 'client wants to revoke the given refresh token' do post revocation_token_endpoint_url, { token: token_to_revoke.refresh_token, token_type_hint: 'refresh_token' }, headers authorization_access_token.reload token_to_revoke.reload expect(response).to be_success expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy expect(authorization_access_token).to_not be_revoked end end end end doorkeeper-2.2.1/spec/requests/flows/client_credentials_spec.rb0000644000076400007640000000346412544753400024053 0ustar pravipravirequire 'spec_helper_integration' describe 'Client Credentials Request' do let(:client) { FactoryGirl.create :application } context 'a valid request' do it 'authorizes the client and returns the token response' do headers = authorization client.uid, client.secret params = { grant_type: 'client_credentials' } post '/oauth/token', params, headers should_have_json 'access_token', Doorkeeper::AccessToken.first.token should_have_json_within 'expires_in', Doorkeeper.configuration.access_token_expires_in, 1 should_not_have_json 'scope' should_not_have_json 'refresh_token' should_not_have_json 'error' should_not_have_json 'error_description' end context 'with scopes' do before do optional_scopes_exist :write end it 'adds the scope to the token an returns in the response' do headers = authorization client.uid, client.secret params = { grant_type: 'client_credentials', scope: 'write' } post '/oauth/token', params, headers should_have_json 'access_token', Doorkeeper::AccessToken.first.token should_have_json 'scope', 'write' end end end context 'an invalid request' do it 'does not authorize the client and returns the error' do headers = {} params = { grant_type: 'client_credentials' } post '/oauth/token', params, headers should_have_json 'error', 'invalid_client' should_have_json 'error_description', translated_error_message(:invalid_client) should_not_have_json 'access_token' expect(response.status).to eq(401) end end def authorization(username, password) credentials = ActionController::HttpAuthentication::Basic.encode_credentials username, password { 'HTTP_AUTHORIZATION' => credentials } end end doorkeeper-2.2.1/spec/requests/protected_resources/0000755000076400007640000000000012544753400021603 5ustar pravipravidoorkeeper-2.2.1/spec/requests/protected_resources/metal_spec.rb0000644000076400007640000000064312544753400024247 0ustar pravipravirequire 'spec_helper_integration' describe 'ActionController::Metal API' do before do @client = FactoryGirl.create(:application) @resource = User.create!(name: 'Joe', password: 'sekret') @token = client_is_authorized(@client, @resource) end it 'client requests protected resource with valid token' do get "/metal.json?access_token=#{@token.token}" should_have_json 'ok', true end end doorkeeper-2.2.1/spec/requests/protected_resources/private_api_spec.rb0000644000076400007640000000536412544753400025455 0ustar pravipravirequire 'spec_helper_integration' feature 'Private API' do background do @client = FactoryGirl.create(:application) @resource = User.create!(name: 'Joe', password: 'sekret') @token = client_is_authorized(@client, @resource) end scenario 'client requests protected resource with valid token' do with_access_token_header @token.token visit '/full_protected_resources' expect(page.body).to have_content('index') end scenario 'client requests protected resource with disabled header authentication' do config_is_set :access_token_methods, [:from_access_token_param] with_access_token_header @token.token visit '/full_protected_resources' response_status_should_be 401 end scenario 'client attempts to request protected resource with invalid token' do with_access_token_header 'invalid' visit '/full_protected_resources' response_status_should_be 401 end scenario 'client attempts to request protected resource with expired token' do @token.update_attribute :expires_in, -100 # expires token with_access_token_header @token.token visit '/full_protected_resources' response_status_should_be 401 end scenario 'client requests protected resource with permanent token' do @token.update_attribute :expires_in, nil # never expires with_access_token_header @token.token visit '/full_protected_resources' expect(page.body).to have_content('index') end scenario 'access token with no default scopes' do Doorkeeper.configuration.instance_eval { @default_scopes = Doorkeeper::OAuth::Scopes.from_array([:public]) @scopes = default_scopes + optional_scopes } @token.update_attribute :scopes, 'dummy' with_access_token_header @token.token visit '/full_protected_resources' response_status_should_be 403 end scenario 'access token with no allowed scopes' do @token.update_attribute :scopes, nil with_access_token_header @token.token visit '/full_protected_resources/1.json' response_status_should_be 403 end scenario 'access token with one of allowed scopes' do @token.update_attribute :scopes, 'admin' with_access_token_header @token.token visit '/full_protected_resources/1.json' expect(page.body).to have_content('show') end scenario 'access token with another of allowed scopes' do @token.update_attribute :scopes, 'write' with_access_token_header @token.token visit '/full_protected_resources/1.json' expect(page.body).to have_content('show') end scenario 'access token with both allowed scopes' do @token.update_attribute :scopes, 'write admin' with_access_token_header @token.token visit '/full_protected_resources/1.json' expect(page.body).to have_content('show') end end doorkeeper-2.2.1/spec/requests/endpoints/0000755000076400007640000000000012544753400017523 5ustar pravipravidoorkeeper-2.2.1/spec/requests/endpoints/token_spec.rb0000644000076400007640000000500512544753400022202 0ustar pravipravirequire 'spec_helper_integration' describe 'Token endpoint' do before do client_exists authorization_code_exists application: @client, scopes: 'public' end it 'respond with correct headers' do post token_endpoint_url(code: @authorization.token, client: @client) should_have_header 'Pragma', 'no-cache' should_have_header 'Cache-Control', 'no-store' should_have_header 'Content-Type', 'application/json; charset=utf-8' end it 'accepts client credentials with basic auth header' do post token_endpoint_url( code: @authorization.token, redirect_uri: @client.redirect_uri ), {}, 'HTTP_AUTHORIZATION' => basic_auth_header_for_client(@client) should_have_json 'access_token', Doorkeeper::AccessToken.first.token end it 'returns null for expires_in when a permanent token is set' do config_is_set(:access_token_expires_in, nil) post token_endpoint_url(code: @authorization.token, client: @client) should_have_json 'access_token', Doorkeeper::AccessToken.first.token should_not_have_json 'expires_in' end it 'returns unsupported_grant_type for invalid grant_type param' do post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'nothing') should_not_have_json 'access_token' should_have_json 'error', 'unsupported_grant_type' should_have_json 'error_description', translated_error_message('unsupported_grant_type') end it 'returns unsupported_grant_type for disabled grant flows' do config_is_set(:grant_flows, ['implicit']) post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'authorization_code') should_not_have_json 'access_token' should_have_json 'error', 'unsupported_grant_type' should_have_json 'error_description', translated_error_message('unsupported_grant_type') end it 'returns unsupported_grant_type when refresh_token is not in use' do post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'refresh_token') should_not_have_json 'access_token' should_have_json 'error', 'unsupported_grant_type' should_have_json 'error_description', translated_error_message('unsupported_grant_type') end it 'returns invalid_request if grant_type is missing' do post token_endpoint_url(code: @authorization.token, client: @client, grant_type: '') should_not_have_json 'access_token' should_have_json 'error', 'invalid_request' should_have_json 'error_description', translated_error_message('invalid_request') end end doorkeeper-2.2.1/spec/requests/endpoints/authorization_spec.rb0000644000076400007640000000423112544753400023762 0ustar pravipravirequire 'spec_helper_integration' feature 'Authorization endpoint' do background do config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') } client_exists(name: 'MyApp') end scenario 'requires resource owner to be authenticated' do visit authorization_endpoint_url(client: @client) i_should_see 'Sign in' i_should_be_on '/' end context 'with authenticated resource owner' do background do create_resource_owner sign_in end scenario 'displays the authorization form' do visit authorization_endpoint_url(client: @client) i_should_see 'Authorize MyApp to use your account?' end scenario 'displays all requested scopes' do default_scopes_exist :public optional_scopes_exist :write visit authorization_endpoint_url(client: @client, scope: 'public write') i_should_see 'Access your public data' i_should_see 'Update your data' end end context 'with a invalid request' do background do create_resource_owner sign_in end scenario 'displays the related error' do visit authorization_endpoint_url(client: @client, response_type: '') i_should_not_see 'Authorize' i_should_see_translated_error_message :unsupported_response_type end scenario "displays unsupported_response_type error when using a disabled response type" do config_is_set(:grant_flows, ['implicit']) visit authorization_endpoint_url(client: @client, response_type: 'code') i_should_not_see "Authorize" i_should_see_translated_error_message :unsupported_response_type end end context 'forgery protection enabled' do background do create_resource_owner sign_in end scenario 'raises exception on forged requests' do skip 'TODO: need to add request helpers to this feature spec' allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request) allowing_forgery_protection do post "/oauth/authorize", client_id: @client.uid, redirect_uri: @client.redirect_uri, response_type: 'code' end end end end doorkeeper-2.2.1/spec/models/0000755000076400007640000000000012544753400015130 5ustar pravipravidoorkeeper-2.2.1/spec/models/doorkeeper/0000755000076400007640000000000012544753400017267 5ustar pravipravidoorkeeper-2.2.1/spec/models/doorkeeper/access_token_spec.rb0000644000076400007640000003033712544753400023275 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper describe AccessToken do subject { FactoryGirl.build(:access_token) } it { should be_valid } it_behaves_like 'an accessible token' it_behaves_like 'a revocable token' it_behaves_like 'a unique token' do let(:factory_name) { :access_token } end describe :generate_token do it 'generates a token using the default method' do FactoryGirl.create :access_token token = FactoryGirl.create :access_token expect(token.token).to be_a(String) end it 'generates a token using a custom object' do module CustomGeneratorArgs def self.generate(opts = {}) "custom_generator_token_#{opts[:resource_owner_id]}" end end Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::CustomGeneratorArgs" end token = FactoryGirl.create :access_token expect(token.token).to match(%r{custom_generator_token_\d+}) end it 'allows the custom generator to access the application details' do module CustomGeneratorArgs def self.generate(opts = {}) "custom_generator_token_#{opts[:application].name}" end end Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::CustomGeneratorArgs" end token = FactoryGirl.create :access_token expect(token.token).to match(%r{custom_generator_token_Application \d+}) end it 'allows the custom generator to access the scopes' do module CustomGeneratorArgs def self.generate(opts = {}) "custom_generator_token_#{opts[:scopes].count}_#{opts[:scopes]}" end end Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::CustomGeneratorArgs" end token = FactoryGirl.create :access_token, scopes: 'public write' expect(token.token).to eq 'custom_generator_token_2_public write' end it 'allows the custom generator to access the expiry length' do module CustomGeneratorArgs def self.generate(opts = {}) "custom_generator_token_#{opts[:expires_in]}" end end Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::CustomGeneratorArgs" end token = FactoryGirl.create :access_token expect(token.token).to eq 'custom_generator_token_7200' end it 'raises an error if the custom object does not support generate' do module NoGenerate end Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::NoGenerate" end expect { FactoryGirl.create :access_token }.to( raise_error(Doorkeeper::Errors::UnableToGenerateToken)) end it 'raises an error if the custom object does not exist' do Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator "Doorkeeper::NotReal" end expect { FactoryGirl.create :access_token }.to( raise_error(Doorkeeper::Errors::TokenGeneratorNotFound)) end end describe :refresh_token do it 'has empty refresh token if it was not required' do token = FactoryGirl.create :access_token expect(token.refresh_token).to be_nil end it 'generates a refresh token if it was requested' do token = FactoryGirl.create :access_token, use_refresh_token: true expect(token.refresh_token).not_to be_nil end it 'is not valid if token exists' do token1 = FactoryGirl.create :access_token, use_refresh_token: true token2 = FactoryGirl.create :access_token, use_refresh_token: true token2.send :write_attribute, :refresh_token, token1.refresh_token expect(token2).not_to be_valid end it 'expects database to raise an error if refresh tokens are the same' do token1 = FactoryGirl.create :access_token, use_refresh_token: true token2 = FactoryGirl.create :access_token, use_refresh_token: true expect do token2.write_attribute :refresh_token, token1.refresh_token token2.save(validate: false) end.to raise_error end end describe 'validations' do it 'is valid without resource_owner_id' do # For client credentials flow subject.resource_owner_id = nil should be_valid end end describe '#same_credential?' do context 'with default parameters' do let(:resource_owner_id) { 100 } let(:application) { FactoryGirl.create :application } let(:default_attributes) do { application: application, resource_owner_id: resource_owner_id } end let(:access_token1) { FactoryGirl.create :access_token, default_attributes } context 'the second token has the same owner and same app' do let(:access_token2) { FactoryGirl.create :access_token, default_attributes } it 'success' do expect(access_token1.same_credential?(access_token2)).to be_truthy end end context 'the second token has same owner and different app' do let(:other_application) { FactoryGirl.create :application } let(:access_token2) { FactoryGirl.create :access_token, application: other_application, resource_owner_id: resource_owner_id } it 'fail' do expect(access_token1.same_credential?(access_token2)).to be_falsey end end context 'the second token has different owner and different app' do let(:other_application) { FactoryGirl.create :application } let(:access_token2) { FactoryGirl.create :access_token, application: other_application, resource_owner_id: 42 } it 'fail' do expect(access_token1.same_credential?(access_token2)).to be_falsey end end context 'the second token has different owner and same app' do let(:access_token2) { FactoryGirl.create :access_token, application: application, resource_owner_id: 42 } it 'fail' do expect(access_token1.same_credential?(access_token2)).to be_falsey end end end end describe '#acceptable?' do context 'a token that is not accessible' do let(:token) { FactoryGirl.create(:access_token, created_at: 6.hours.ago) } it 'should return false' do expect(token.acceptable?(nil)).to be false end end context 'a token that has the incorrect scopes' do let(:token) { FactoryGirl.create(:access_token) } it 'should return false' do expect(token.acceptable?(['public'])).to be false end end context 'a token is acceptable with the correct scopes' do let(:token) do token = FactoryGirl.create(:access_token) token[:scopes] = 'public' token end it 'should return true' do expect(token.acceptable?(['public'])).to be true end end end describe '.revoke_all_for' do let(:resource_owner) { double(id: 100) } let(:application) { FactoryGirl.create :application } let(:default_attributes) do { application: application, resource_owner_id: resource_owner.id } end it 'revokes all tokens for given application and resource owner' do FactoryGirl.create :access_token, default_attributes AccessToken.revoke_all_for application.id, resource_owner AccessToken.all.each do |token| expect(token).to be_revoked end end it 'matches application' do FactoryGirl.create :access_token, default_attributes.merge(application: FactoryGirl.create(:application)) AccessToken.revoke_all_for application.id, resource_owner expect(AccessToken.all).not_to be_empty end it 'matches resource owner' do FactoryGirl.create :access_token, default_attributes.merge(resource_owner_id: 90) AccessToken.revoke_all_for application.id, resource_owner expect(AccessToken.all).not_to be_empty end end describe '.matching_token_for' do let(:resource_owner_id) { 100 } let(:application) { FactoryGirl.create :application } let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public write') } let(:default_attributes) do { application: application, resource_owner_id: resource_owner_id, scopes: scopes.to_s } end it 'returns only one token' do token = FactoryGirl.create :access_token, default_attributes last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to eq(token) end it 'accepts resource owner as object' do resource_owner = double(to_key: true, id: 100) token = FactoryGirl.create :access_token, default_attributes last_token = AccessToken.matching_token_for(application, resource_owner, scopes) expect(last_token).to eq(token) end it 'accepts nil as resource owner' do token = FactoryGirl.create :access_token, default_attributes.merge(resource_owner_id: nil) last_token = AccessToken.matching_token_for(application, nil, scopes) expect(last_token).to eq(token) end it 'excludes revoked tokens' do FactoryGirl.create :access_token, default_attributes.merge(revoked_at: 1.day.ago) last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches the application' do FactoryGirl.create :access_token, default_attributes.merge(application: FactoryGirl.create(:application)) last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches the resource owner' do FactoryGirl.create :access_token, default_attributes.merge(resource_owner_id: 2) last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches token with fewer scopes' do FactoryGirl.create :access_token, default_attributes.merge(scopes: 'public') last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches token with different scopes' do FactoryGirl.create :access_token, default_attributes.merge(scopes: 'public email') last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches token with more scopes' do FactoryGirl.create :access_token, default_attributes.merge(scopes: 'public write email') last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'matches application scopes' do application = FactoryGirl.create :application, scopes: "private read" FactoryGirl.create :access_token, default_attributes.merge( application: application ) last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to be_nil end it 'returns the last created token' do FactoryGirl.create :access_token, default_attributes.merge(created_at: 1.day.ago) token = FactoryGirl.create :access_token, default_attributes last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes) expect(last_token).to eq(token) end it 'returns as_json hash' do token = FactoryGirl.create :access_token, default_attributes token_hash = { resource_owner_id: token.resource_owner_id, scopes: token.scopes, expires_in_seconds: token.expires_in_seconds, application: { uid: token.application.uid }, created_at: token.created_at.to_i, } expect(token.as_json).to eq token_hash end end end end doorkeeper-2.2.1/spec/models/doorkeeper/application_spec.rb0000644000076400007640000001446412544753400023142 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper describe Application do let(:require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', true) } let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', false) } let(:new_application) { FactoryGirl.build(:application) } let(:uid) { SecureRandom.hex(8) } let(:secret) { SecureRandom.hex(8) } context 'application_owner is enabled' do before do Doorkeeper.configure do orm DOORKEEPER_ORM enable_application_owner end end context 'application owner is not required' do before(:each) do unset_require_owner end it 'is valid given valid attributes' do expect(new_application).to be_valid end end context 'application owner is required' do before(:each) do require_owner @owner = FactoryGirl.build_stubbed(:user) end it 'is invalid without an owner' do expect(new_application).not_to be_valid end it 'is valid with an owner' do new_application.owner = @owner expect(new_application).to be_valid end end end it 'is invalid without a name' do new_application.name = nil expect(new_application).not_to be_valid end it 'generates uid on create' do expect(new_application.uid).to be_nil new_application.save expect(new_application.uid).not_to be_nil end it 'generates uid on create unless one is set' do new_application.uid = uid new_application.save expect(new_application.uid).to eq(uid) end it 'is invalid without uid' do new_application.save new_application.uid = nil expect(new_application).not_to be_valid end it 'is invalid without redirect_uri' do new_application.save new_application.redirect_uri = nil expect(new_application).not_to be_valid end it 'checks uniqueness of uid' do app1 = FactoryGirl.create(:application) app2 = FactoryGirl.create(:application) app2.uid = app1.uid expect(app2).not_to be_valid end it 'expects database to throw an error when uids are the same' do app1 = FactoryGirl.create(:application) app2 = FactoryGirl.create(:application) app2.uid = app1.uid expect { app2.save!(validate: false) }.to raise_error end it 'generate secret on create' do expect(new_application.secret).to be_nil new_application.save expect(new_application.secret).not_to be_nil end it 'generate secret on create unless one is set' do new_application.secret = secret new_application.save expect(new_application.secret).to eq(secret) end it 'is invalid without secret' do new_application.save new_application.secret = nil expect(new_application).not_to be_valid end describe 'destroy related models on cascade' do before(:each) do new_application.save end it 'should destroy its access grants' do FactoryGirl.create(:access_grant, application: new_application) expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1) end it 'should destroy its access tokens' do FactoryGirl.create(:access_token, application: new_application) FactoryGirl.create(:access_token, application: new_application, revoked_at: Time.now) expect do new_application.destroy end.to change { Doorkeeper::AccessToken.count }.by(-2) end end describe :authorized_for do let(:resource_owner) { double(:resource_owner, id: 10) } it 'is empty if the application is not authorized for anyone' do expect(Application.authorized_for(resource_owner)).to be_empty end it 'returns only application for a specific resource owner' do FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id + 1) token = FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id) expect(Application.authorized_for(resource_owner)).to eq([token.application]) end it 'excludes revoked tokens' do FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago) expect(Application.authorized_for(resource_owner)).to be_empty end it 'returns all applications that have been authorized' do token1 = FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id) token2 = FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id) expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application]) end it 'returns only one application even if it has been authorized twice' do application = FactoryGirl.create(:application) FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id, application: application) FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id, application: application) expect(Application.authorized_for(resource_owner)).to eq([application]) end it 'should fail to mass assign a new application', if: ::Rails::VERSION::MAJOR < 4 do mass_assign = { name: 'Something', redirect_uri: 'http://somewhere.com/something', uid: 123, secret: 'something' } expect(Application.create(mass_assign).uid).not_to eq(123) end end describe :authenticate do it 'finds the application via uid/secret' do app = FactoryGirl.create :application authenticated = Application.by_uid_and_secret(app.uid, app.secret) expect(authenticated).to eq(app) end end if Doorkeeper.configuration.orm == :active_record describe :scopes do it 'fails on missing column with an upgrade notice' do app = FactoryGirl.build :application no_scopes_app = double(attributes: []) allow(Application).to receive(:new).and_return(no_scopes_app) expect { app.scopes }.to raise_error( NameError, /Missing column: `applications.scopes`/ ) end end end end end doorkeeper-2.2.1/spec/models/doorkeeper/access_grant_spec.rb0000644000076400007640000000145112544753400023263 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper::AccessGrant do subject { FactoryGirl.build(:access_grant) } it { should be_valid } it_behaves_like 'an accessible token' it_behaves_like 'a revocable token' it_behaves_like 'a unique token' do let(:factory_name) { :access_grant } end describe 'validations' do it 'is invalid without resource_owner_id' do subject.resource_owner_id = nil should_not be_valid end it 'is invalid without application_id' do subject.application_id = nil should_not be_valid end it 'is invalid without token' do subject.save subject.token = nil should_not be_valid end it 'is invalid without expires_in' do subject.expires_in = nil should_not be_valid end end end doorkeeper-2.2.1/spec/validators/0000755000076400007640000000000012544753400016015 5ustar pravipravidoorkeeper-2.2.1/spec/validators/redirect_uri_validator_spec.rb0000644000076400007640000000445312544753400024107 0ustar pravipravirequire 'spec_helper_integration' describe RedirectUriValidator do subject do FactoryGirl.create(:application) end it 'is valid when the uri is a uri' do subject.redirect_uri = 'https://example.com/callback' expect(subject).to be_valid end it 'accepts native redirect uri' do subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob' expect(subject).to be_valid end it 'rejects if test uri is disabled' do allow(RedirectUriValidator).to receive(:native_redirect_uri).and_return(nil) subject.redirect_uri = 'urn:some:test' expect(subject).not_to be_valid end it 'is invalid when the uri is not a uri' do subject.redirect_uri = ']' expect(subject).not_to be_valid expect(subject.errors[:redirect_uri].first).to eq('must be a valid URI.') end it 'is invalid when the uri is relative' do subject.redirect_uri = '/abcd' expect(subject).not_to be_valid expect(subject.errors[:redirect_uri].first).to eq('must be an absolute URI.') end it 'is invalid when the uri has a fragment' do subject.redirect_uri = 'https://example.com/abcd#xyz' expect(subject).not_to be_valid expect(subject.errors[:redirect_uri].first).to eq('cannot contain a fragment.') end it 'is invalid when the uri has a query parameter' do subject.redirect_uri = 'https://example.com/abcd?xyz=123' expect(subject).to be_valid end context 'force secured uri' do it 'accepts an valid uri' do subject.redirect_uri = 'https://example.com/callback' expect(subject).to be_valid end it 'accepts native redirect uri' do subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob' expect(subject).to be_valid end it 'accepts a non secured protocol when disabled' do subject.redirect_uri = 'http://example.com/callback' allow(Doorkeeper.configuration).to receive( :force_ssl_in_redirect_uri ).and_return(false) expect(subject).to be_valid end it 'invalidates the uri when the uri does not use a secure protocol' do subject.redirect_uri = 'http://example.com/callback' expect(subject).not_to be_valid error = subject.errors[:redirect_uri].first expect(error).to eq('must be an HTTPS/SSL URI.') end end end doorkeeper-2.2.1/spec/support/0000755000076400007640000000000012544753400015361 5ustar pravipravidoorkeeper-2.2.1/spec/support/dependencies/0000755000076400007640000000000012544753400020007 5ustar pravipravidoorkeeper-2.2.1/spec/support/dependencies/factory_girl.rb0000644000076400007640000000006412544753400023020 0ustar pravipravirequire 'factory_girl' FactoryGirl.find_definitions doorkeeper-2.2.1/spec/support/shared/0000755000076400007640000000000012544753400016627 5ustar pravipravidoorkeeper-2.2.1/spec/support/shared/controllers_shared_context.rb0000644000076400007640000000315012544753400024613 0ustar pravipravishared_context 'valid token', token: :valid do let :token_string do '1A2B3C4D' end let :token do double(Doorkeeper::AccessToken, accessible?: true, includes_scope?: true, acceptable?: true) end before :each do allow(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) end end shared_context 'invalid token', token: :invalid do let :token_string do '1A2B3C4D' end let :token do double(Doorkeeper::AccessToken, accessible?: false, revoked?: false, expired?: false, includes_scope?: false, acceptable?: false) end before :each do allow(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) end end shared_context 'authenticated resource owner' do before do user = double(:resource, id: 1) allow(Doorkeeper.configuration).to receive(:authenticate_resource_owner) { proc { user } } end end shared_context 'not authenticated resource owner' do before do allow(Doorkeeper.configuration).to receive(:authenticate_resource_owner) { proc { redirect_to '/' } } end end shared_context 'valid authorization request' do let :authorization do double(:authorization, valid?: true, authorize: true, success_redirect_uri: 'http://something.com/cb?code=token') end before do allow(controller).to receive(:authorization) { authorization } end end shared_context 'invalid authorization request' do let :authorization do double(:authorization, valid?: false, authorize: false, redirect_on_error?: false) end before do allow(controller).to receive(:authorization) { authorization } end end doorkeeper-2.2.1/spec/support/shared/models_shared_examples.rb0000644000076400007640000000256112544753400023667 0ustar pravipravishared_examples 'an accessible token' do describe :accessible? do it 'is accessible if token is not expired' do allow(subject).to receive(:expired?).and_return(false) should be_accessible end it 'is not accessible if token is expired' do allow(subject).to receive(:expired?).and_return(true) should_not be_accessible end end end shared_examples 'a revocable token' do describe :accessible? do before { subject.save! } it 'is accessible if token is not revoked' do expect(subject).to be_accessible end it 'is not accessible if token is revoked' do subject.revoke expect(subject).not_to be_accessible end end end shared_examples 'a unique token' do describe :token do it 'is generated before validation' do expect { subject.valid? }.to change { subject.token }.from(nil) end it 'is not valid if token exists' do token1 = FactoryGirl.create factory_name token2 = FactoryGirl.create factory_name token2.token = token1.token expect(token2).not_to be_valid end it 'expects database to throw an error when tokens are the same' do token1 = FactoryGirl.create factory_name token2 = FactoryGirl.create factory_name token2.token = token1.token expect do token2.save!(validate: false) end.to raise_error end end end doorkeeper-2.2.1/spec/support/orm/0000755000076400007640000000000012544753400016156 5ustar pravipravidoorkeeper-2.2.1/spec/support/orm/mongoid.rb0000644000076400007640000000043512544753400020141 0ustar pravipraviDatabaseCleaner[:mongoid].strategy = :truncation DatabaseCleaner[:mongoid].clean_with :truncation RSpec.configure do |config| config.before do Doorkeeper::Application.create_indexes Doorkeeper::AccessGrant.create_indexes Doorkeeper::AccessToken.create_indexes end end doorkeeper-2.2.1/spec/support/orm/mongo_mapper.rb0000644000076400007640000000045612544753400021173 0ustar pravipraviDatabaseCleaner[:mongo_mapper].strategy = :truncation DatabaseCleaner[:mongo_mapper].clean_with :truncation RSpec.configure do |config| config.before :suite do Doorkeeper::Application.create_indexes Doorkeeper::AccessGrant.create_indexes Doorkeeper::AccessToken.create_indexes end end doorkeeper-2.2.1/spec/support/orm/active_record.rb0000644000076400007640000000015312544753400021313 0ustar pravipravi# load schema to in memory sqlite ActiveRecord::Migration.verbose = false load Rails.root + 'db/schema.rb' doorkeeper-2.2.1/spec/support/helpers/0000755000076400007640000000000012544753400017023 5ustar pravipravidoorkeeper-2.2.1/spec/support/helpers/request_spec_helper.rb0000644000076400007640000000333212544753400023412 0ustar pravipravimodule RequestSpecHelper def i_should_see(content) expect(page).to have_content(content) end def i_should_not_see(content) expect(page).to have_no_content(content) end def i_should_be_on(path) expect(current_path).to eq(path) end def url_should_have_param(param, value) expect(current_params[param]).to eq(value) end def url_should_not_have_param(param) expect(current_params).not_to have_key(param) end def current_params Rack::Utils.parse_query(current_uri.query) end def current_uri URI.parse(page.current_url) end def should_have_header(header, value) expect(headers[header]).to eq(value) end def with_access_token_header(token) with_header 'Authorization', "Bearer #{token}" end def with_header(header, value) page.driver.header header, value end def basic_auth_header_for_client(client) ActionController::HttpAuthentication::Basic.encode_credentials client.uid, client.secret end def should_have_json(key, value) expect(JSON.parse(response.body).fetch(key)).to eq(value) end def should_have_json_within(key, value, range) expect(JSON.parse(response.body).fetch(key)).to be_within(range).of(value) end def should_not_have_json(key) expect(JSON.parse(response.body)).not_to have_key(key) end def sign_in visit '/' click_on 'Sign in' end def i_should_see_translated_error_message(key) i_should_see translated_error_message(key) end def translated_error_message(key) I18n.translate key, scope: [:doorkeeper, :errors, :messages] end def response_status_should_be(status) expect(page.driver.response.status.to_i).to eq(status) end end RSpec.configuration.send :include, RequestSpecHelper doorkeeper-2.2.1/spec/support/helpers/model_helper.rb0000644000076400007640000000247412544753400022016 0ustar pravipravimodule ModelHelper def client_exists(client_attributes = {}) @client = FactoryGirl.create(:application, client_attributes) end def create_resource_owner @resource_owner = User.create!(name: 'Joe', password: 'sekret') end def authorization_code_exists(options = {}) @authorization = FactoryGirl.create(:access_grant, options) end def access_grant_should_exist_for(client, resource_owner) grant = Doorkeeper::AccessGrant.first expect(grant.application).to eq(client) grant.resource_owner_id == resource_owner.id end def access_token_should_exist_for(client, resource_owner) grant = Doorkeeper::AccessToken.first expect(grant.application).to eq(client) grant.resource_owner_id == resource_owner.id end def access_grant_should_not_exist expect(Doorkeeper::AccessGrant.all).to be_empty end def access_token_should_not_exist expect(Doorkeeper::AccessToken.all).to be_empty end def access_grant_should_have_scopes(*args) grant = Doorkeeper::AccessGrant.first expect(grant.scopes).to eq(Doorkeeper::OAuth::Scopes.from_array(args)) end def access_token_should_have_scopes(*args) grant = Doorkeeper::AccessToken.last expect(grant.scopes).to eq(Doorkeeper::OAuth::Scopes.from_array(args)) end end RSpec.configuration.send :include, ModelHelper doorkeeper-2.2.1/spec/support/helpers/url_helper.rb0000644000076400007640000000407312544753400021515 0ustar pravipravimodule UrlHelper def token_endpoint_url(options = {}) parameters = { code: options[:code], client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil), client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil), redirect_uri: options[:redirect_uri] || (options[:client] ? options[:client].redirect_uri : nil), grant_type: options[:grant_type] || 'authorization_code' } "/oauth/token?#{build_query(parameters)}" end def password_token_endpoint_url(options = {}) parameters = { code: options[:code], client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil), client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil), username: options[:resource_owner_username] || (options[:resource_owner] ? options[:resource_owner].name : nil), password: options[:resource_owner_password] || (options[:resource_owner] ? options[:resource_owner].password : nil), grant_type: 'password' } "/oauth/token?#{build_query(parameters)}" end def authorization_endpoint_url(options = {}) parameters = { client_id: options[:client_id] || options[:client].uid, redirect_uri: options[:redirect_uri] || options[:client].redirect_uri, response_type: options[:response_type] || 'code', scope: options[:scope], state: options[:state] }.reject { |k, v| v.blank? } "/oauth/authorize?#{build_query(parameters)}" end def refresh_token_endpoint_url(options = {}) parameters = { refresh_token: options[:refresh_token], client_id: options[:client_id] || options[:client].uid, client_secret: options[:client_secret] || options[:client].secret, grant_type: options[:grant_type] || 'refresh_token' } "/oauth/token?#{build_query(parameters)}" end def revocation_token_endpoint_url '/oauth/revoke' end def build_query(hash) Rack::Utils.build_query(hash) end end RSpec.configuration.send :include, UrlHelper doorkeeper-2.2.1/spec/support/helpers/config_helper.rb0000644000076400007640000000042312544753400022153 0ustar pravipravimodule ConfigHelper def config_is_set(setting, value = nil, &block) setting_ivar = "@#{setting}" value = block_given? ? block : value Doorkeeper.configuration.instance_variable_set(setting_ivar, value) end end RSpec.configuration.send :include, ConfigHelper doorkeeper-2.2.1/spec/support/helpers/authorization_request_helper.rb0000644000076400007640000000263512544753400025365 0ustar pravipravimodule AuthorizationRequestHelper def resource_owner_is_authenticated(resource_owner = nil) resource_owner ||= User.create!(name: 'Joe', password: 'sekret') Doorkeeper.configuration.instance_variable_set(:@authenticate_resource_owner, proc { resource_owner }) end def resource_owner_is_not_authenticated Doorkeeper.configuration.instance_variable_set(:@authenticate_resource_owner, proc { redirect_to('/sign_in') }) end def default_scopes_exist(*scopes) Doorkeeper.configuration.instance_variable_set(:@default_scopes, Doorkeeper::OAuth::Scopes.from_array(scopes)) end def optional_scopes_exist(*scopes) Doorkeeper.configuration.instance_variable_set(:@optional_scopes, Doorkeeper::OAuth::Scopes.from_array(scopes)) end def client_should_be_authorized(client) expect(client.access_grants.size).to eq(1) end def client_should_not_be_authorized(client) expect(client.size).to eq(0) end def i_should_be_on_client_callback(client) expect(client.redirect_uri).to eq("#{current_uri.scheme}://#{current_uri.host}#{current_uri.path}") end def allowing_forgery_protection(&block) _original_value = ActionController::Base.allow_forgery_protection ActionController::Base.allow_forgery_protection = true block.call ensure ActionController::Base.allow_forgery_protection = _original_value end end RSpec.configuration.send :include, AuthorizationRequestHelper doorkeeper-2.2.1/spec/support/helpers/access_token_request_helper.rb0000644000076400007640000000055012544753400025120 0ustar pravipravimodule AccessTokenRequestHelper def client_is_authorized(client, resource_owner, access_token_attributes = {}) attributes = { application: client, resource_owner_id: resource_owner.id }.merge(access_token_attributes) FactoryGirl.create(:access_token, attributes) end end RSpec.configuration.send :include, AccessTokenRequestHelper doorkeeper-2.2.1/spec/dummy/0000755000076400007640000000000012544753400015000 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/db/0000755000076400007640000000000012544753400015365 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/db/schema.rb0000644000076400007640000000576612544753400017170 0ustar pravipravi# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # # Note that this schema.rb definition is the authoritative source for your # database schema. If you need to create the application database on another # system, you should be using db:schema:load, not running all the migrations # from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 20141209001746) do create_table "oauth_access_grants", force: true do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false t.string "token", null: false t.integer "expires_in", null: false t.string "redirect_uri", limit: 2048, null: false t.datetime "created_at", null: false t.datetime "revoked_at" t.string "scopes" end add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true create_table "oauth_access_tokens", force: true do |t| t.integer "resource_owner_id" t.integer "application_id" t.string "token", null: false t.string "refresh_token" t.integer "expires_in" t.datetime "revoked_at" t.datetime "created_at", null: false t.string "scopes" end add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id" add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true create_table "oauth_applications", force: true do |t| t.string "name", null: false t.string "uid", null: false t.string "secret", null: false t.string "redirect_uri", limit: 2048, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "owner_id" t.string "owner_type" t.string "scopes", default: "", null: false end add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type" add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true create_table "users", force: true do |t| t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "password" end end doorkeeper-2.2.1/spec/dummy/db/migrate/0000755000076400007640000000000012544753400017015 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb0000644000076400007640000000042212544753400026044 0ustar pravipraviclass AddOwnerToApplication < ActiveRecord::Migration def change add_column :oauth_applications, :owner_id, :integer, null: true add_column :oauth_applications, :owner_type, :string, null: true add_index :oauth_applications, [:owner_id, :owner_type] end end doorkeeper-2.2.1/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb0000644000076400007640000000024312544753400027561 0ustar pravipraviclass AddScopesToOauthApplications < ActiveRecord::Migration def change add_column :oauth_applications, :scopes, :string, null: false, default: '' end end doorkeeper-2.2.1/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb0000644000076400007640000000016412544753400025364 0ustar pravipraviclass AddPasswordToUsers < ActiveRecord::Migration def change add_column :users, :password, :string end end doorkeeper-2.2.1/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb0000644000076400007640000000254012544753400026030 0ustar pravipraviclass CreateDoorkeeperTables < ActiveRecord::Migration def change create_table :oauth_applications do |t| t.string :name, null: false t.string :uid, null: false t.string :secret, null: false t.string :redirect_uri, null: false, limit: 2048 t.timestamps end add_index :oauth_applications, :uid, unique: true create_table :oauth_access_grants do |t| t.integer :resource_owner_id, null: false t.integer :application_id, null: false t.string :token, null: false t.integer :expires_in, null: false t.string :redirect_uri, null: false, limit: 2048 t.datetime :created_at, null: false t.datetime :revoked_at t.string :scopes end add_index :oauth_access_grants, :token, unique: true create_table :oauth_access_tokens do |t| t.integer :resource_owner_id t.integer :application_id t.string :token, null: false t.string :refresh_token t.integer :expires_in t.datetime :revoked_at t.datetime :created_at, null: false t.string :scopes end add_index :oauth_access_tokens, :token, unique: true add_index :oauth_access_tokens, :resource_owner_id add_index :oauth_access_tokens, :refresh_token, unique: true end end doorkeeper-2.2.1/spec/dummy/db/migrate/20111122132257_create_users.rb0000644000076400007640000000022312544753400023460 0ustar pravipraviclass CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.timestamps end end end doorkeeper-2.2.1/spec/dummy/config/0000755000076400007640000000000012544753400016245 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/config/environment.rb0000644000076400007640000000022512544753400021135 0ustar pravipravi# Load the rails application require File.expand_path('../application', __FILE__) # Initialize the rails application Dummy::Application.initialize! doorkeeper-2.2.1/spec/dummy/config/mongo.yml0000644000076400007640000000030612544753400020106 0ustar pravipravidefaults: &defaults host: 127.0.0.1 port: 27017 development: <<: *defaults database: doorkeeper-mongomapper-development test: <<: *defaults database: doorkeeper-mongomapper-test-suite doorkeeper-2.2.1/spec/dummy/config/locales/0000755000076400007640000000000012544753400017667 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/config/locales/doorkeeper.en.yml0000644000076400007640000000014712544753400023154 0ustar pravipravien: doorkeeper: scopes: public: "Access your public data" write: "Update your data" doorkeeper-2.2.1/spec/dummy/config/environments/0000755000076400007640000000000012544753400020774 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/config/environments/test.rb0000644000076400007640000000430212544753400022277 0ustar pravipraviDummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Configure static asset server for tests with Cache-Control for performance config.static_cache_control = 'public, max-age=3600' if Rails.version.to_i < 4 # Log error messages when you accidentally call methods on nil config.whiny_nils = true end if Rails.version.to_i >= 4 # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. config.eager_load = false config.i18n.enforce_available_locales = true end # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. # config.action_mailer.delivery_method = :test # Use SQL instead of Active Record's schema dumper when creating the test database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql # Print deprecation notices to the stderr config.active_support.deprecation = :stderr config.eager_load = true if DOORKEEPER_ORM == :active_record config.active_record.table_name_prefix = TABLE_NAME_PREFIX.to_s config.active_record.table_name_suffix = TABLE_NAME_SUFFIX.to_s end end doorkeeper-2.2.1/spec/dummy/config/environments/production.rb0000644000076400007640000000420512544753400023510 0ustar pravipraviDummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb # Code is not reloaded between requests config.cache_classes = true # Full error reports are disabled and caching is turned on config.consider_all_requests_local = false config.action_controller.perform_caching = true # Disable Rails's static asset server (Apache or nginx will already do this) config.serve_static_assets = false # Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true # Defaults to Rails.root.join("public/assets") # config.assets.manifest = YOUR_PATH # Specifies the header that your server uses for sending files # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # See everything in the log (default is :info) # config.log_level = :debug # Use a different logger for distributed setups # config.logger = SyslogLogger.new # Use a different cache store in production # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # config.assets.precompile += %w( search.js ) # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false # Enable threaded mode # config.threadsafe! # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true # Send deprecation notices to registered listeners config.active_support.deprecation = :notify config.eager_load = true end doorkeeper-2.2.1/spec/dummy/config/environments/development.rb0000644000076400007640000000175712544753400023655 0ustar pravipraviDummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send # config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger config.active_support.deprecation = :log # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin # Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true config.eager_load = false end doorkeeper-2.2.1/spec/dummy/config/boot.rb0000644000076400007640000000037612544753400017543 0ustar pravipravirequire 'rubygems' require 'bundler/setup' orm = ENV['BUNDLE_GEMFILE'].match(/Gemfile\.(.+)\.rb/) unless defined?(DOORKEEPER_ORM) DOORKEEPER_ORM = (orm && orm[1]) || :active_record end $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) doorkeeper-2.2.1/spec/dummy/config/initializers/0000755000076400007640000000000012544753400020753 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/config/initializers/session_store.rb0000644000076400007640000000062712544753400024204 0ustar pravipravi# Be sure to restart your server when you modify this file. Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") # Dummy::Application.config.session_store :active_record_store doorkeeper-2.2.1/spec/dummy/config/initializers/secret_token.rb0000644000076400007640000000104012544753400023760 0ustar pravipravi# Be sure to restart your server when you modify this file. # Your secret key for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. Dummy::Application.config.secret_key_base = Dummy::Application.config.secret_token = 'c00157b5a1bb6181792f0f4a8a080485de7bab9987e6cf159dc74c4f0573345c1bfa713b5d756e1491fc0b098567e8a619e2f8d268eda86a20a720d05d633780' doorkeeper-2.2.1/spec/dummy/config/initializers/wrap_parameters.rb0000644000076400007640000000072112544753400024474 0ustar pravipravi# Be sure to restart your server when you modify this file. # # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] end # Disable root element in JSON by default. ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end doorkeeper-2.2.1/spec/dummy/config/initializers/doorkeeper.rb0000644000076400007640000001073612544753400023446 0ustar pravipraviDoorkeeper.configure do # Change the ORM that doorkeeper will use. # Currently supported options are :active_record, :mongoid2, :mongoid3, # :mongoid4, :mongo_mapper orm DOORKEEPER_ORM # This block will be called to check whether the resource owner is authenticated or not. resource_owner_authenticator do # Put your resource owner authentication logic here. User.where(id: session[:user_id]).first || redirect_to(root_url, alert: 'Needs sign in.') end # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. # admin_authenticator do # # Put your admin authentication logic here. # # Example implementation: # Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url) # end # Authorization Code expiration time (default 10 minutes). # authorization_code_expires_in 10.minutes # Access token expiration time (default 2 hours). # If you want to disable expiration, set this to nil. # access_token_expires_in 2.hours # Reuse access token for the same resource owner within an application (disabled by default) # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383 # reuse_access_token # Issue access tokens with refresh token (disabled by default) use_refresh_token # Provide support for an owner to be assigned to each registered application (disabled by default) # Optional parameter :confirmation => true (default false) if you want to enforce ownership of # a registered application # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support # enable_application_owner :confirmation => false # Define access token scopes for your provider # For more information go to # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes default_scopes :public optional_scopes :write, :update # Change the way client credentials are retrieved from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:client_id` and `:client_secret` params from the `params` object. # Check out the wiki for more information on customization # client_credentials :from_basic, :from_params # Change the way access token is authenticated from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:access_token` or `:bearer_token` params from the `params` object. # Check out the wiki for more information on customization # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param # Change the native redirect uri for client apps # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi) # # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob' # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled # by default in non-development environments). OAuth2 delegates security in # communication to the HTTPS protocol so it is wise to keep this enabled. # # force_ssl_in_redirect_uri !Rails.env.development? # Specify what grant flows are enabled in array of Strings. The valid # strings and the flows they enable are: # # "authorization_code" => Authorization Code Grant Flow # "implicit" => Implicit Grant Flow # "password" => Resource Owner Password Credentials Grant Flow # "client_credentials" => Client Credentials Grant Flow # # If not specified, Doorkeeper enables authorization_code and # client_credentials. # # implicit and password grant flows have risks that you should understand # before enabling: # http://tools.ietf.org/html/rfc6819#section-4.4.2 # http://tools.ietf.org/html/rfc6819#section-4.4.3 # # grant_flows %w(authorization_code client_credentials) # Under some circumstances you might want to have applications auto-approved, # so that the user skips the authorization step. # For example if dealing with a trusted application. # skip_authorization do |resource_owner, client| # client.superapp? or resource_owner.admin? # end # WWW-Authenticate Realm (default "Doorkeeper"). realm "Doorkeeper" end doorkeeper-2.2.1/spec/dummy/config/initializers/backtrace_silencers.rb0000644000076400007640000000062412544753400025270 0ustar pravipravi# Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! doorkeeper-2.2.1/spec/dummy/config/database.yml0000644000076400007640000000034312544753400020534 0ustar pravipravidevelopment: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000 test: adapter: sqlite3 database: ":memory:" timeout: 500 production: adapter: sqlite3 database: ":memory:" timeout: 500 doorkeeper-2.2.1/spec/dummy/config/routes.rb0000644000076400007640000000274312544753400020121 0ustar pravipraviRails.application.routes.draw do use_doorkeeper use_doorkeeper scope: 'scope' scope 'inner_space' do use_doorkeeper scope: 'scope' do controllers authorizations: 'custom_authorizations', tokens: 'custom_authorizations', applications: 'custom_authorizations', token_info: 'custom_authorizations' as authorizations: 'custom_auth', tokens: 'custom_token', token_info: 'custom_token_info' end end scope 'space' do use_doorkeeper do controllers authorizations: 'custom_authorizations', tokens: 'custom_authorizations', applications: 'custom_authorizations', token_info: 'custom_authorizations' as authorizations: 'custom_auth', tokens: 'custom_token', token_info: 'custom_token_info' end end scope 'outer_space' do use_doorkeeper do controllers authorizations: 'custom_authorizations', tokens: 'custom_authorizations', token_info: 'custom_authorizations' as authorizations: 'custom_auth', tokens: 'custom_token', token_info: 'custom_token_info' skip_controllers :tokens, :applications, :token_info end end get 'metal.json' => 'metal#index' get '/callback', to: 'home#callback' get '/sign_in', to: 'home#sign_in' resources :semi_protected_resources resources :full_protected_resources root to: 'home#index' end doorkeeper-2.2.1/spec/dummy/config/mongoid3.yml0000644000076400007640000000055212544753400020511 0ustar pravipravidevelopment: sessions: default: database: doorkeeper-mongoid3-development hosts: - localhost:27017 options: consistency: :strong safe: true test: sessions: default: database: doorkeeper-mongoid3-test hosts: - localhost:27017 options: consistency: :strong safe: true doorkeeper-2.2.1/spec/dummy/config/mongoid2.yml0000644000076400007640000000031412544753400020504 0ustar pravipravidevelopment: database: doorkeeper-development persist_in_safe_mode: true autocreate_indexes: true test: database: doorkeeper-mongoid2-test persist_in_safe_mode: true autocreate_indexes: true doorkeeper-2.2.1/spec/dummy/config/mongoid4.yml0000644000076400007640000000050712544753400020512 0ustar pravipravidevelopment: sessions: default: database: doorkeeper-mongoid4-development hosts: - localhost:27017 options: write: w: 1 test: sessions: default: database: doorkeeper-mongoid4-test hosts: - localhost:27017 options: write: w: 1 doorkeeper-2.2.1/spec/dummy/config/application.rb0000644000076400007640000000406412544753400021101 0ustar pravipravirequire File.expand_path('../boot', __FILE__) require 'action_controller/railtie' require 'sprockets/railtie' Bundler.require :default require 'yaml' orm = if DOORKEEPER_ORM =~ /mongoid/ Mongoid.load!(File.join(File.dirname(File.expand_path(__FILE__)), "#{DOORKEEPER_ORM}.yml")) :mongoid else DOORKEEPER_ORM end require "#{orm}/railtie" module Dummy class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer if defined?(ActiveRecord) && Rails.version.to_i < 4 config.active_record.whitelist_attributes = true end # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. config.i18n.load_path += Dir[Rails.root.join('../../', 'config/locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :en # Configure the default encoding used in templates for Ruby 1.9. config.encoding = 'utf-8' # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] # Enable the asset pipeline config.assets.enabled = true # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' I18n.enforce_available_locales = false end end doorkeeper-2.2.1/spec/dummy/script/0000755000076400007640000000000012544753400016304 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/script/rails0000755000076400007640000000044712544753400017351 0ustar pravipravi#!/usr/bin/env ruby # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. APP_PATH = File.expand_path('../../config/application', __FILE__) require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' doorkeeper-2.2.1/spec/dummy/public/0000755000076400007640000000000012544753400016256 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/public/422.html0000644000076400007640000000130712544753400017454 0ustar pravipravi The change you wanted was rejected (422)

The change you wanted was rejected.

Maybe you tried to change something you didn't have access to.

doorkeeper-2.2.1/spec/dummy/public/500.html0000644000076400007640000000133012544753400017445 0ustar pravipravi We're sorry, but something went wrong (500)

We're sorry, but something went wrong.

We've been notified about this issue and we'll take a look at it shortly.

doorkeeper-2.2.1/spec/dummy/public/favicon.ico0000644000076400007640000000000012544753400020365 0ustar pravipravidoorkeeper-2.2.1/spec/dummy/public/404.html0000644000076400007640000000133012544753400017450 0ustar pravipravi The page you were looking for doesn't exist (404)

The page you were looking for doesn't exist.

You may have mistyped the address or the page may have moved.

doorkeeper-2.2.1/spec/dummy/config.ru0000644000076400007640000000023312544753400016613 0ustar pravipravi# This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run Dummy::Application doorkeeper-2.2.1/spec/dummy/app/0000755000076400007640000000000012544753400015560 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/helpers/0000755000076400007640000000000012544753400017222 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/helpers/application_helper.rb0000644000076400007640000000015712544753400023414 0ustar pravipravimodule ApplicationHelper def current_user @current_user ||= User.find_by_id(session[:user_id]) end end doorkeeper-2.2.1/spec/dummy/app/models/0000755000076400007640000000000012544753400017043 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/models/user.rb0000644000076400007640000000115212544753400020345 0ustar pravipravicase DOORKEEPER_ORM.to_s when "active_record" class User < ActiveRecord::Base end when /mongoid/ class User include Mongoid::Document include Mongoid::Timestamps field :name, type: String field :password, type: String end when "mongo_mapper" class User include MongoMapper::Document timestamps! key :name, String key :password, String end end class User if ::Rails.version.to_i < 4 || defined?(::ProtectedAttributes) attr_accessible :name, :password end def self.authenticate!(name, password) User.where(name: name, password: password).first end end doorkeeper-2.2.1/spec/dummy/app/views/0000755000076400007640000000000012544753400016715 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/views/layouts/0000755000076400007640000000000012544753400020415 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/views/layouts/application.html.erb0000644000076400007640000000024112544753400024352 0ustar pravipravi Dummy <%= csrf_meta_tags %> <%= link_to "Sign in", '/sign_in' %> <%= yield %> doorkeeper-2.2.1/spec/dummy/app/views/home/0000755000076400007640000000000012544753400017645 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/views/home/index.html.erb0000644000076400007640000000000012544753400022377 0ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/controllers/0000755000076400007640000000000012544753400020126 5ustar pravipravidoorkeeper-2.2.1/spec/dummy/app/controllers/semi_protected_resources_controller.rb0000644000076400007640000000034612544753400030021 0ustar pravipraviclass SemiProtectedResourcesController < ApplicationController before_filter :doorkeeper_authorize!, only: :index def index render text: 'protected index' end def show render text: 'non protected show' end end doorkeeper-2.2.1/spec/dummy/app/controllers/full_protected_resources_controller.rb0000644000076400007640000000042712544753400030026 0ustar pravipraviclass FullProtectedResourcesController < ApplicationController before_filter -> { doorkeeper_authorize! :write, :admin }, only: :show before_filter :doorkeeper_authorize!, only: :index def index render text: 'index' end def show render text: 'show' end end doorkeeper-2.2.1/spec/dummy/app/controllers/metal_controller.rb0000644000076400007640000000041312544753400024016 0ustar pravipraviclass MetalController < ActionController::Metal include AbstractController::Callbacks include ActionController::Head include Doorkeeper::Rails::Helpers before_filter :doorkeeper_authorize! def index self.response_body = { ok: true }.to_json end end doorkeeper-2.2.1/spec/dummy/app/controllers/home_controller.rb0000644000076400007640000000057612544753400023656 0ustar pravipraviclass HomeController < ApplicationController def index end def sign_in session[:user_id] = if Rails.env.development? User.first || User.create!(name: 'Joe', password: 'sekret') else User.first end redirect_to '/' end def callback render text: 'ok' end end doorkeeper-2.2.1/spec/dummy/app/controllers/custom_authorizations_controller.rb0000644000076400007640000000031112544753400027366 0ustar pravipraviclass CustomAuthorizationsController < ::ApplicationController %w(index show new create edit update destroy).each do |action| define_method action do render nothing: true end end end doorkeeper-2.2.1/spec/dummy/app/controllers/application_controller.rb0000644000076400007640000000012012544753400025212 0ustar pravipraviclass ApplicationController < ActionController::Base protect_from_forgery end doorkeeper-2.2.1/spec/dummy/Rakefile0000644000076400007640000000041612544753400016446 0ustar pravipravi#!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) Dummy::Application.load_tasks doorkeeper-2.2.1/spec/generators/0000755000076400007640000000000012544753400016016 5ustar pravipravidoorkeeper-2.2.1/spec/generators/migration_generator_spec.rb0000644000076400007640000000076312544753400023422 0ustar pravipravirequire 'spec_helper_integration' require 'generators/doorkeeper/migration_generator' describe 'Doorkeeper::MigrationGenerator' do include GeneratorSpec::TestCase tests Doorkeeper::MigrationGenerator destination ::File.expand_path('../tmp/dummy', __FILE__) describe 'after running the generator' do before :each do prepare_destination run_generator end it 'creates a migration' do assert_migration 'db/migrate/create_doorkeeper_tables.rb' end end end doorkeeper-2.2.1/spec/generators/views_generator_spec.rb0000644000076400007640000000163512544753400022565 0ustar pravipravirequire 'spec_helper_integration' require 'generators/doorkeeper/views_generator' describe Doorkeeper::Generators::ViewsGenerator do include GeneratorSpec::TestCase tests Doorkeeper::Generators::ViewsGenerator destination File.expand_path('../tmp/dummy', __FILE__) before :each do prepare_destination end it 'create all views' do run_generator assert_file 'app/views/doorkeeper/applications/_form.html.erb' assert_file 'app/views/doorkeeper/applications/edit.html.erb' assert_file 'app/views/doorkeeper/applications/index.html.erb' assert_file 'app/views/doorkeeper/applications/new.html.erb' assert_file 'app/views/doorkeeper/applications/show.html.erb' assert_file 'app/views/doorkeeper/authorizations/error.html.erb' assert_file 'app/views/doorkeeper/authorizations/new.html.erb' assert_file 'app/views/doorkeeper/authorized_applications/index.html.erb' end end doorkeeper-2.2.1/spec/generators/install_generator_spec.rb0000644000076400007640000000174012544753400023073 0ustar pravipravirequire 'spec_helper_integration' require 'generators/doorkeeper/install_generator' describe 'Doorkeeper::InstallGenerator' do include GeneratorSpec::TestCase tests Doorkeeper::InstallGenerator destination ::File.expand_path('../tmp/dummy', __FILE__) describe 'after running the generator' do before :each do prepare_destination FileUtils.mkdir(::File.expand_path('config', Pathname(destination_root))) FileUtils.mkdir(::File.expand_path('db', Pathname(destination_root))) FileUtils.copy_file(::File.expand_path('../templates/routes.rb', __FILE__), ::File.expand_path('config/routes.rb', Pathname.new(destination_root))) run_generator end it 'creates an initializer file' do assert_file 'config/initializers/doorkeeper.rb' end it 'copies the locale file' do assert_file 'config/locales/doorkeeper.en.yml' end it 'adds sample route' do assert_file 'config/routes.rb', /use_doorkeeper/ end end end doorkeeper-2.2.1/spec/generators/templates/0000755000076400007640000000000012544753400020014 5ustar pravipravidoorkeeper-2.2.1/spec/generators/templates/routes.rb0000644000076400007640000000004612544753400021662 0ustar pravipraviRails.application.routes.draw do end doorkeeper-2.2.1/spec/generators/application_owner_generator_spec.rb0000644000076400007640000000136312544753400025143 0ustar pravipravirequire 'spec_helper_integration' require 'generators/doorkeeper/application_owner_generator' describe 'Doorkeeper::ApplicationOwnerGenerator' do include GeneratorSpec::TestCase tests Doorkeeper::ApplicationOwnerGenerator destination ::File.expand_path('../tmp/dummy', __FILE__) describe 'after running the generator' do before :each do prepare_destination FileUtils.mkdir(::File.expand_path('config', Pathname(destination_root))) FileUtils.copy_file(::File.expand_path('../templates/routes.rb', __FILE__), ::File.expand_path('config/routes.rb', Pathname.new(destination_root))) run_generator end it 'creates a migration' do assert_migration 'db/migrate/add_owner_to_application.rb' end end end doorkeeper-2.2.1/spec/lib/0000755000076400007640000000000012544753400014413 5ustar pravipravidoorkeeper-2.2.1/spec/lib/server_spec.rb0000644000076400007640000000302512544753400017260 0ustar pravipravirequire 'spec_helper' require 'active_support/all' require 'doorkeeper/errors' require 'doorkeeper/server' describe Doorkeeper::Server do let(:fake_class) { double :fake_class } subject do described_class.new end describe '.authorization_request' do it 'raises error when strategy does not exist' do expect do subject.authorization_request(:duh) end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy) end it 'raises error when strategy does not match phase' do expect do subject.token_request(:code) end.to raise_error(Doorkeeper::Errors::InvalidTokenStrategy) end context 'when only Authorization Code strategy is enabled' do before do allow(Doorkeeper.configuration). to receive(:grant_flows). and_return(['authorization_code']) end it 'raises error when using the disabled Implicit strategy' do expect do subject.authorization_request(:token) end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy) end it 'raises error when using the disabled Client Credentials strategy' do expect do subject.token_request(:client_credentials) end.to raise_error(Doorkeeper::Errors::InvalidTokenStrategy) end end it 'builds the request with selected strategy' do stub_const 'Doorkeeper::Request::Code', fake_class expect(fake_class).to receive(:build).with(subject) subject.authorization_request :code end end end doorkeeper-2.2.1/spec/lib/config_spec.rb0000644000076400007640000002121112544753400017214 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper, 'configuration' do subject { Doorkeeper.configuration } describe 'resource_owner_authenticator' do it 'sets the block that is accessible via authenticate_resource_owner' do block = proc {} Doorkeeper.configure do orm DOORKEEPER_ORM resource_owner_authenticator &block end expect(subject.authenticate_resource_owner).to eq(block) end end describe 'setup_orm_adapter' do it 'adds specific error message to NameError exception' do expect do Doorkeeper.configure { orm 'hibernate' } end.to raise_error(NameError, /ORM adapter not found \(hibernate\)/) end it 'does not change other exceptions' do allow_any_instance_of(String).to receive(:classify) { raise NoMethodError } expect do Doorkeeper.configure { orm 'hibernate' } end.to raise_error(NoMethodError, /ORM adapter not found \(hibernate\)/) end end describe 'admin_authenticator' do it 'sets the block that is accessible via authenticate_admin' do block = proc {} Doorkeeper.configure do orm DOORKEEPER_ORM admin_authenticator(&block) end expect(subject.authenticate_admin).to eq(block) end end describe 'access_token_expires_in' do it 'has 2 hours by default' do expect(subject.access_token_expires_in).to eq(2.hours) end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM access_token_expires_in 4.hours end expect(subject.access_token_expires_in).to eq(4.hours) end it 'can be set to nil' do Doorkeeper.configure do orm DOORKEEPER_ORM access_token_expires_in nil end expect(subject.access_token_expires_in).to be_nil end end describe 'scopes' do it 'has default scopes' do Doorkeeper.configure do orm DOORKEEPER_ORM default_scopes :public end expect(subject.default_scopes).to include('public') end it 'has optional scopes' do Doorkeeper.configure do orm DOORKEEPER_ORM optional_scopes :write, :update end expect(subject.optional_scopes).to include('write', 'update') end it 'has all scopes' do Doorkeeper.configure do orm DOORKEEPER_ORM default_scopes :normal optional_scopes :admin end expect(subject.scopes).to include('normal', 'admin') end end describe 'use_refresh_token' do it 'is false by default' do expect(subject.refresh_token_enabled?).to be_falsey end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM use_refresh_token end expect(subject.refresh_token_enabled?).to be_truthy end it "does not includes 'refresh_token' in authorization_response_types" do expect(subject.token_grant_types).not_to include 'refresh_token' end context "is enabled" do before do Doorkeeper.configure { orm DOORKEEPER_ORM use_refresh_token } end it "includes 'refresh_token' in authorization_response_types" do expect(subject.token_grant_types).to include 'refresh_token' end end end describe 'client_credentials' do it 'has defaults order' do expect(subject.client_credentials_methods).to eq([:from_basic, :from_params]) end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM client_credentials :from_digest, :from_params end expect(subject.client_credentials_methods).to eq([:from_digest, :from_params]) end end describe 'force_ssl_in_redirect_uri' do it 'is true by default in non-development environments' do expect(subject.force_ssl_in_redirect_uri).to be_truthy end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM force_ssl_in_redirect_uri(false) end expect(subject.force_ssl_in_redirect_uri).to be_falsey end end describe 'access_token_credentials' do it 'has defaults order' do expect(subject.access_token_methods).to eq([:from_bearer_authorization, :from_access_token_param, :from_bearer_param]) end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM access_token_methods :from_access_token_param, :from_bearer_param end expect(subject.access_token_methods).to eq([:from_access_token_param, :from_bearer_param]) end end describe 'enable_application_owner' do it 'is disabled by default' do expect(Doorkeeper.configuration.enable_application_owner?).not_to be_truthy end context 'when enabled without confirmation' do before do Doorkeeper.configure do orm DOORKEEPER_ORM enable_application_owner end end it 'adds support for application owner' do expect(Doorkeeper::Application.new).to respond_to :owner end it 'Doorkeeper.configuration.confirm_application_owner? returns false' do expect(Doorkeeper.configuration.confirm_application_owner?).not_to be_truthy end end context 'when enabled with confirmation set to true' do before do Doorkeeper.configure do orm DOORKEEPER_ORM enable_application_owner confirmation: true end end it 'adds support for application owner' do expect(Doorkeeper::Application.new).to respond_to :owner end it 'Doorkeeper.configuration.confirm_application_owner? returns true' do expect(Doorkeeper.configuration.confirm_application_owner?).to be_truthy end end end describe 'realm' do it 'is \'Doorkeeper\' by default' do expect(Doorkeeper.configuration.realm).to eq('Doorkeeper') end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM realm 'Example' end expect(subject.realm).to eq('Example') end end describe "grant_flows" do it "is set to all grant flows by default" do expect(Doorkeeper.configuration.grant_flows). to eq(%w(authorization_code client_credentials)) end it "can change the value" do Doorkeeper.configure { orm DOORKEEPER_ORM grant_flows [ 'authorization_code', 'implicit' ] } expect(subject.grant_flows).to eq ['authorization_code', 'implicit'] end context "when including 'authorization_code'" do before do Doorkeeper.configure { orm DOORKEEPER_ORM grant_flows ['authorization_code'] } end it "includes 'code' in authorization_response_types" do expect(subject.authorization_response_types).to include 'code' end it "includes 'authorization_code' in token_grant_types" do expect(subject.token_grant_types).to include 'authorization_code' end end context "when including 'implicit'" do before do Doorkeeper.configure { orm DOORKEEPER_ORM grant_flows ['implicit'] } end it "includes 'token' in authorization_response_types" do expect(subject.authorization_response_types).to include 'token' end end context "when including 'password'" do before do Doorkeeper.configure { orm DOORKEEPER_ORM grant_flows ['password'] } end it "includes 'password' in token_grant_types" do expect(subject.token_grant_types).to include 'password' end end context "when including 'client_credentials'" do before do Doorkeeper.configure { orm DOORKEEPER_ORM grant_flows ['client_credentials'] } end it "includes 'client_credentials' in token_grant_types" do expect(subject.token_grant_types).to include 'client_credentials' end end end it 'raises an exception when configuration is not set' do old_config = Doorkeeper.configuration Doorkeeper.module_eval do @config = nil end expect do Doorkeeper.configuration end.to raise_error Doorkeeper::MissingConfiguration Doorkeeper.module_eval do @config = old_config end end describe 'access_token_generator' do it 'is \'Doorkeeper::OAuth::Helpers::UniqueToken\' by default' do expect(Doorkeeper.configuration.access_token_generator).to( eq('Doorkeeper::OAuth::Helpers::UniqueToken') ) end it 'can change the value' do Doorkeeper.configure do orm DOORKEEPER_ORM access_token_generator 'Example' end expect(subject.access_token_generator).to eq('Example') end end end doorkeeper-2.2.1/spec/lib/oauth/0000755000076400007640000000000012544753400015533 5ustar pravipravidoorkeeper-2.2.1/spec/lib/oauth/invalid_token_response_spec.rb0000644000076400007640000000142612544753400023641 0ustar pravipravirequire 'spec_helper' require 'active_model' require 'doorkeeper' require 'doorkeeper/oauth/invalid_token_response' module Doorkeeper::OAuth describe InvalidTokenResponse do describe '#name' do it { expect(subject.name).to eq(:invalid_token) } end describe '#status' do it { expect(subject.status).to eq(:unauthorized) } end describe :from_access_token do it 'revoked' do response = InvalidTokenResponse.from_access_token double(revoked?: true, expired?: true) expect(response.description).to include('revoked') end it 'expired' do response = InvalidTokenResponse.from_access_token double(revoked?: false, expired?: true) expect(response.description).to include('expired') end end end end doorkeeper-2.2.1/spec/lib/oauth/authorization/0000755000076400007640000000000012544753400020433 5ustar pravipravidoorkeeper-2.2.1/spec/lib/oauth/authorization/uri_builder_spec.rb0000644000076400007640000000262512544753400024304 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/string' require 'uri' require 'rack/utils' require 'doorkeeper/oauth/authorization/uri_builder' module Doorkeeper::OAuth::Authorization describe URIBuilder do subject { Object.new.class.send :include, URIBuilder } describe :uri_with_query do it 'returns the uri with query' do uri = subject.uri_with_query 'http://example.com/', parameter: 'value' expect(uri).to eq('http://example.com/?parameter=value') end it 'rejects nil values' do uri = subject.uri_with_query 'http://example.com/', parameter: '' expect(uri).to eq('http://example.com/?') end it 'preserves original query parameters' do uri = subject.uri_with_query 'http://example.com/?query1=value', parameter: 'value' expect(uri).to match(/query1=value/) expect(uri).to match(/parameter=value/) end end describe :uri_with_fragment do it 'returns uri with parameters as fragments' do uri = subject.uri_with_fragment 'http://example.com/', parameter: 'value' expect(uri).to eq('http://example.com/#parameter=value') end it 'preserves original query parameters' do uri = subject.uri_with_fragment 'http://example.com/?query1=value1', parameter: 'value' expect(uri).to eq('http://example.com/?query1=value1#parameter=value') end end end end doorkeeper-2.2.1/spec/lib/oauth/client_credentials/0000755000076400007640000000000012544753400021366 5ustar pravipravidoorkeeper-2.2.1/spec/lib/oauth/client_credentials/issuer_spec.rb0000644000076400007640000000456412544753400024250 0ustar pravipravirequire 'spec_helper' require 'active_support/all' require 'doorkeeper/oauth/client_credentials/issuer' class Doorkeeper::OAuth::ClientCredentialsRequest describe Issuer do let(:creator) { double :acces_token_creator } let(:server) do double( :server, access_token_expires_in: 100, custom_access_token_expires_in: ->(_app) { nil } ) end let(:validation) { double :validation, valid?: true } subject { Issuer.new(server, validation) } describe :create do let(:client) { double :client, id: 'some-id' } let(:scopes) { 'some scope' } it 'creates and sets the token' do expect(creator).to receive(:call).and_return('token') subject.create client, scopes, creator expect(subject.token).to eq('token') end it 'creates with correct token parameters' do expect(creator).to receive(:call).with( client, scopes, expires_in: 100, use_refresh_token: false ) subject.create client, scopes, creator end it 'has error set to :server_error if creator fails' do expect(creator).to receive(:call).and_return(false) subject.create client, scopes, creator expect(subject.error).to eq(:server_error) end context 'when validation fails' do before do allow(validation).to receive(:valid?).and_return(false) allow(validation).to receive(:error).and_return(:validation_error) expect(creator).not_to receive(:create) end it 'has error set from validation' do subject.create client, scopes, creator expect(subject.error).to eq(:validation_error) end it 'returns false' do expect(subject.create(client, scopes, creator)).to be_falsey end end context 'with custom expirations' do let(:custom_ttl) { 1233 } let(:server) do double( :server, custom_access_token_expires_in: ->(_app) { custom_ttl } ) end it 'creates with correct token parameters' do expect(creator).to receive(:call).with( client, scopes, expires_in: custom_ttl, use_refresh_token: false ) subject.create client, scopes, creator end end end end end doorkeeper-2.2.1/spec/lib/oauth/client_credentials/creator_spec.rb0000644000076400007640000000113212544753400024361 0ustar pravipravirequire 'spec_helper_integration' class Doorkeeper::OAuth::ClientCredentialsRequest describe Creator do let(:client) { FactoryGirl.create :application } let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public') } it 'creates a new token' do expect do subject.call(client, scopes) end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'returns false if creation fails' do expect(Doorkeeper::AccessToken).to receive(:create).and_return(false) created = subject.call(client, scopes) expect(created).to be_falsey end end end doorkeeper-2.2.1/spec/lib/oauth/client_credentials/validation_spec.rb0000644000076400007640000000424512544753400025064 0ustar pravipravirequire 'spec_helper' require 'active_support/all' require 'doorkeeper/oauth/client_credentials/validation' class Doorkeeper::OAuth::ClientCredentialsRequest describe Validation do let(:server) { double :server, scopes: nil } let(:application) { double scopes: nil } let(:client) { double application: application } let(:request) { double :request, client: client, scopes: nil } subject { Validation.new(server, request) } it 'is valid with valid request' do expect(subject).to be_valid end it 'is invalid when client is not present' do allow(request).to receive(:client).and_return(nil) expect(subject).not_to be_valid end context 'with scopes' do it 'is invalid when scopes are not included in the server' do server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email' allow(server).to receive(:scopes).and_return(server_scopes) allow(request).to receive(:scopes).and_return( Doorkeeper::OAuth::Scopes.from_string 'invalid') expect(subject).not_to be_valid end context 'with application scopes' do it 'is valid when scopes are included in the application' do application_scopes = Doorkeeper::OAuth::Scopes.from_string 'app' server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email app' allow(application).to receive(:scopes).and_return(application_scopes) allow(server).to receive(:scopes).and_return(server_scopes) allow(request).to receive(:scopes).and_return(application_scopes) expect(subject).to be_valid end it 'is invalid when scopes are not included in the application' do application_scopes = Doorkeeper::OAuth::Scopes.from_string 'app' server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email app' allow(application).to receive(:scopes).and_return(application_scopes) allow(server).to receive(:scopes).and_return(server_scopes) allow(request).to receive(:scopes).and_return( Doorkeeper::OAuth::Scopes.from_string 'email') expect(subject).not_to be_valid end end end end end doorkeeper-2.2.1/spec/lib/oauth/refresh_token_request_spec.rb0000644000076400007640000000761512544753400023511 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe RefreshTokenRequest do let(:server) do double :server, access_token_expires_in: 2.minutes, custom_access_token_expires_in: -> (_oauth_client) { nil } end let(:refresh_token) do FactoryGirl.create(:access_token, use_refresh_token: true) end let(:client) { refresh_token.application } let(:credentials) { Client::Credentials.new(client.uid, client.secret) } subject { RefreshTokenRequest.new server, refresh_token, credentials } it 'issues a new token for the client' do expect do subject.authorize end.to change { client.access_tokens.count }.by(1) expect(client.reload.access_tokens.last.expires_in).to eq(120) end it 'issues a new token for the client with custom expires_in' do server = double :server, access_token_expires_in: 2.minutes, custom_access_token_expires_in: ->(_oauth_client) { 1234 } RefreshTokenRequest.new(server, refresh_token, credentials).authorize expect(client.reload.access_tokens.last.expires_in).to eq(1234) end it 'revokes the previous token' do expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true) end it 'requires the refresh token' do subject.refresh_token = nil subject.validate expect(subject.error).to eq(:invalid_request) end it 'requires credentials to be valid if provided' do subject.client = nil subject.validate expect(subject.error).to eq(:invalid_client) end it "requires the token's client and current client to match" do subject.client = FactoryGirl.create(:application) subject.validate expect(subject.error).to eq(:invalid_grant) end it 'rejects revoked tokens' do refresh_token.revoke subject.validate expect(subject.error).to eq(:invalid_grant) end it 'accepts expired tokens' do refresh_token.expires_in = -1 refresh_token.save subject.validate expect(subject).to be_valid end context 'clientless access tokens' do let!(:refresh_token) { FactoryGirl.create(:clientless_access_token, use_refresh_token: true) } subject { RefreshTokenRequest.new server, refresh_token, nil } it 'issues a new token without a client' do expect { subject.authorize }.to change { Doorkeeper::AccessToken.count }.by(1) end end context 'with scopes' do let(:refresh_token) do FactoryGirl.create :access_token, use_refresh_token: true, scopes: 'public write' end let(:parameters) { {} } subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters } it 'transfers scopes from the old token to the new token' do subject.authorize expect(Doorkeeper::AccessToken.last.scopes).to eq([:public, :write]) end it 'reduces scopes to the provided scopes' do parameters[:scopes] = 'public' subject.authorize expect(Doorkeeper::AccessToken.last.scopes).to eq([:public]) end it 'validates that scopes are included in the original access token' do parameters[:scopes] = 'public update' subject.validate expect(subject.error).to eq(:invalid_scope) end it 'uses params[:scope] in favor of scopes if present (valid)' do parameters[:scopes] = 'public update' parameters[:scope] = 'public' subject.authorize expect(Doorkeeper::AccessToken.last.scopes).to eq([:public]) end it 'uses params[:scope] in favor of scopes if present (invalid)' do parameters[:scopes] = 'public' parameters[:scope] = 'public update' subject.validate expect(subject.error).to eq(:invalid_scope) end end end end doorkeeper-2.2.1/spec/lib/oauth/token_request_spec.rb0000644000076400007640000000535212544753400021767 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe TokenRequest do let :application do scopes = double(all: ['public']) double(:application, id: 9990, scopes: scopes) end let :pre_auth do double( :pre_auth, client: application, redirect_uri: 'http://tst.com/cb', state: nil, scopes: Scopes.from_string('public'), error: nil, authorizable?: true ) end let :owner do double :owner, id: 7866 end subject do TokenRequest.new(pre_auth, owner) end it 'creates an access token' do expect do subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'returns a code response' do expect(subject.authorize).to be_a(CodeResponse) end it 'does not create token when not authorizable' do allow(pre_auth).to receive(:authorizable?).and_return(false) expect do subject.authorize end.to_not change { Doorkeeper::AccessToken.count } end it 'returns a error response' do allow(pre_auth).to receive(:authorizable?).and_return(false) expect(subject.authorize).to be_a(ErrorResponse) end context 'with custom expirations' do before do Doorkeeper.configure do orm DOORKEEPER_ORM custom_access_token_expires_in do |_oauth_client| 1234 end end end it 'should use the custom ttl' do subject.authorize token = Doorkeeper::AccessToken.first expect(token.expires_in).to eq(1234) end end context 'token reuse' do it 'creates a new token if there are no matching tokens' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) expect do subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'creates a new token if scopes do not match' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) FactoryGirl.create(:access_token, application_id: pre_auth.client.id, resource_owner_id: owner.id, scopes: '') expect do subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'skips token creation if there is a matching one' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) FactoryGirl.create(:access_token, application_id: pre_auth.client.id, resource_owner_id: owner.id, scopes: 'public') expect do subject.authorize end.to_not change { Doorkeeper::AccessToken.count } end end end end doorkeeper-2.2.1/spec/lib/oauth/pre_authorization_spec.rb0000644000076400007640000001050412544753400022640 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe PreAuthorization do let(:server) { server = Doorkeeper.configuration allow(server).to receive(:default_scopes).and_return(Scopes.new) allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile')) server } let(:application) do application = double :application allow(application).to receive(:scopes).and_return(Scopes.from_string('')) application end let(:client) do double :client, redirect_uri: 'http://tst.com/auth', application: application end let :attributes do { response_type: 'code', redirect_uri: 'http://tst.com/auth', state: 'save-this' } end subject do PreAuthorization.new(server, client, attributes) end it 'is authorizable when request is valid' do expect(subject).to be_authorizable end it 'accepts code as response type' do subject.response_type = 'code' expect(subject).to be_authorizable end it 'accepts token as response type' do allow(server).to receive(:grant_flows).and_return(['implicit']) subject.response_type = 'token' expect(subject).to be_authorizable end context 'when using default grant flows' do it 'accepts "code" as response type' do subject.response_type = 'code' expect(subject).to be_authorizable end it 'accepts "token" as response type' do allow(server).to receive(:grant_flows).and_return(['implicit']) subject.response_type = 'token' expect(subject).to be_authorizable end end context 'when authorization code grant flow is disabled' do before do allow(server).to receive(:grant_flows).and_return(['implicit']) end it 'does not accept "code" as response type' do subject.response_type = 'code' expect(subject).not_to be_authorizable end end context 'when implicit grant flow is disabled' do before do allow(server).to receive(:grant_flows).and_return(['authorization_code']) end it 'does not accept "token" as response type' do subject.response_type = 'token' expect(subject).not_to be_authorizable end end context 'client application does not restrict valid scopes' do it 'accepts valid scopes' do subject.scope = 'public' expect(subject).to be_authorizable end it 'rejects (globally) non-valid scopes' do subject.scope = 'invalid' expect(subject).not_to be_authorizable end end context 'client application restricts valid scopes' do let(:application) do application = double :application allow(application).to receive(:scopes).and_return(Scopes.from_string('public nonsense')) application end it 'accepts valid scopes' do subject.scope = 'public' expect(subject).to be_authorizable end it 'rejects (globally) non-valid scopes' do subject.scope = 'invalid' expect(subject).not_to be_authorizable end it 'rejects (application level) non-valid scopes' do subject.scope = 'profile' expect(subject).to_not be_authorizable end end it 'uses default scopes when none is required' do allow(server).to receive(:default_scopes).and_return(Scopes.from_string('default')) subject.scope = nil expect(subject.scope).to eq('default') expect(subject.scopes).to eq(Scopes.from_string('default')) end it 'accepts test uri' do subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob' expect(subject).to be_authorizable end it 'matches the redirect uri against client\'s one' do subject.redirect_uri = 'http://nothesame.com' expect(subject).not_to be_authorizable end it 'stores the state' do expect(subject.state).to eq('save-this') end it 'rejects if response type is not allowed' do subject.response_type = 'whops' expect(subject).not_to be_authorizable end it 'requires an existing client' do subject.client = nil expect(subject).not_to be_authorizable end it 'requires a redirect uri' do subject.redirect_uri = nil expect(subject).not_to be_authorizable end end end doorkeeper-2.2.1/spec/lib/oauth/error_response_spec.rb0000644000076400007640000000360112544753400022141 0ustar pravipravirequire 'spec_helper' require 'active_model' require 'doorkeeper/oauth/error' require 'doorkeeper/oauth/error_response' module Doorkeeper::OAuth describe ErrorResponse do describe '#status' do it 'should have a status of unauthorized' do expect(subject.status).to eq(:unauthorized) end end describe :from_request do it 'has the error from request' do error = ErrorResponse.from_request double(error: :some_error) expect(error.name).to eq(:some_error) end it 'ignores state if request does not respond to state' do error = ErrorResponse.from_request double(error: :some_error) expect(error.state).to be_nil end it 'has state if request responds to state' do error = ErrorResponse.from_request double(error: :some_error, state: :hello) expect(error.state).to eq(:hello) end end it 'ignores empty error values' do subject = ErrorResponse.new(error: :some_error, state: nil) expect(subject.body).not_to have_key(:state) end describe '.body' do subject { ErrorResponse.new(name: :some_error, state: :some_state).body } describe '#body' do it { should have_key(:error) } it { should have_key(:error_description) } it { should have_key(:state) } end end describe '.authenticate_info' do let(:error_response) { ErrorResponse.new(name: :some_error, state: :some_state) } subject { error_response.authenticate_info } it { should include("realm=\"#{error_response.realm}\"") } it { should include("error=\"#{error_response.name}\"") } it { should include("error_description=\"#{error_response.description}\"") } end describe '.headers' do subject { ErrorResponse.new(name: :some_error, state: :some_state).headers } it { should include 'WWW-Authenticate' } end end end doorkeeper-2.2.1/spec/lib/oauth/helpers/0000755000076400007640000000000012544753400017175 5ustar pravipravidoorkeeper-2.2.1/spec/lib/oauth/helpers/uri_checker_spec.rb0000644000076400007640000000643312544753400023025 0ustar pravipravirequire 'spec_helper' require 'uri' require 'doorkeeper/oauth/helpers/uri_checker' module Doorkeeper::OAuth::Helpers describe URIChecker do describe '.valid?' do it 'is valid for valid uris' do uri = 'http://app.co' expect(URIChecker.valid?(uri)).to be_truthy end it 'is valid if include path param' do uri = 'http://app.co/path' expect(URIChecker.valid?(uri)).to be_truthy end it 'is valid if include query param' do uri = 'http://app.co/?query=1' expect(URIChecker.valid?(uri)).to be_truthy end it 'is invalid if uri includes fragment' do uri = 'http://app.co/test#fragment' expect(URIChecker.valid?(uri)).to be_falsey end it 'is invalid if scheme is missing' do uri = 'app.co' expect(URIChecker.valid?(uri)).to be_falsey end it 'is invalid if is a relative uri' do uri = '/abc/123' expect(URIChecker.valid?(uri)).to be_falsey end it 'is invalid if is not a url' do uri = 'http://' expect(URIChecker.valid?(uri)).to be_falsey end end describe '.matches?' do it 'is true if both url matches' do uri = client_uri = 'http://app.co/aaa' expect(URIChecker.matches?(uri, client_uri)).to be_truthy end it 'ignores query parameter on comparsion' do uri = 'http://app.co/?query=hello' client_uri = 'http://app.co' expect(URIChecker.matches?(uri, client_uri)).to be_truthy end it 'doesn\'t allow non-matching domains through' do uri = 'http://app.abc/?query=hello' client_uri = 'http://app.co' expect(URIChecker.matches?(uri, client_uri)).to be_falsey end it 'doesn\'t allow non-matching domains that don\'t start at the beginning' do uri = 'http://app.co/?query=hello' client_uri = 'http://example.com?app.co=test' expect(URIChecker.matches?(uri, client_uri)).to be_falsey end end describe '.valid_for_authorization?' do it 'is true if valid and matches' do uri = client_uri = 'http://app.co/aaa' expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_truthy end it 'is false if valid and mismatches' do uri = 'http://app.co/aaa' client_uri = 'http://app.co/bbb' expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_falsey end it 'is true if valid and included in array' do uri = 'http://app.co/aaa' client_uri = "http://example.com/bbb\nhttp://app.co/aaa" expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_truthy end it 'is false if valid and not included in array' do uri = 'http://app.co/aaa' client_uri = "http://example.com/bbb\nhttp://app.co/cc" expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_falsey end it 'is true if valid and matches' do uri = client_uri = 'http://app.co/aaa' expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be true end it 'is false if invalid' do uri = client_uri = 'http://app.co/aaa?waffles=abc' expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be false end end end end doorkeeper-2.2.1/spec/lib/oauth/helpers/scope_checker_spec.rb0000644000076400007640000000357512544753400023343 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/string' require 'doorkeeper/oauth/helpers/scope_checker' require 'doorkeeper/oauth/scopes' module Doorkeeper::OAuth::Helpers describe ScopeChecker, '.valid?' do let(:server_scopes) { Doorkeeper::OAuth::Scopes.new } it 'is valid if scope is present' do server_scopes.add :scope expect(ScopeChecker.valid?('scope', server_scopes)).to be_truthy end it 'is invalid if includes tabs space' do expect(ScopeChecker.valid?("\tsomething", server_scopes)).to be_falsey end it 'is invalid if scope is not present' do expect(ScopeChecker.valid?(nil, server_scopes)).to be_falsey end it 'is invalid if scope is blank' do expect(ScopeChecker.valid?(' ', server_scopes)).to be_falsey end it 'is invalid if includes return space' do expect(ScopeChecker.valid?("scope\r", server_scopes)).to be_falsey end it 'is invalid if includes new lines' do expect(ScopeChecker.valid?("scope\nanother", server_scopes)).to be_falsey end it 'is invalid if any scope is not included in server scopes' do expect(ScopeChecker.valid?('scope another', server_scopes)).to be_falsey end context 'with application_scopes' do let(:server_scopes) do Doorkeeper::OAuth::Scopes.from_string 'common svr' end let(:application_scopes) do Doorkeeper::OAuth::Scopes.from_string 'common' end it 'is valid if scope is included in the server and the application' do expect(ScopeChecker.valid?( 'common', server_scopes, application_scopes )).to be_truthy end it 'is invalid if any scope is not included in the application' do expect(ScopeChecker.valid?( 'svr', server_scopes, application_scopes )).to be_falsey end end end end doorkeeper-2.2.1/spec/lib/oauth/helpers/unique_token_spec.rb0000644000076400007640000000100712544753400023240 0ustar pravipravirequire 'spec_helper' require 'doorkeeper/oauth/helpers/unique_token' module Doorkeeper::OAuth::Helpers describe UniqueToken do let :generator do ->(size) { 'a' * size } end it 'is able to customize the generator method' do token = UniqueToken.generate(generator: generator) expect(token).to eq('a' * 32) end it 'is able to customize the size of the token' do token = UniqueToken.generate(generator: generator, size: 2) expect(token).to eq('aa') end end end doorkeeper-2.2.1/spec/lib/oauth/token_spec.rb0000644000076400007640000000716012544753400020216 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/string' require 'doorkeeper/oauth/token' module Doorkeeper unless defined?(AccessToken) class AccessToken end end module OAuth describe Token do describe :from_request do let(:request) { double.as_null_object } let(:method) do ->(request) { return 'token-value' } end it 'accepts anything that responds to #call' do expect(method).to receive(:call).with(request) Token.from_request request, method end it 'delegates methods received as symbols to Token class' do expect(Token).to receive(:from_params).with(request) Token.from_request request, :from_params end it 'stops at the first credentials found' do not_called_method = double expect(not_called_method).not_to receive(:call) Token.from_request request, ->(r) {}, method, not_called_method end it 'returns the credential from extractor method' do credentials = Token.from_request request, method expect(credentials).to eq('token-value') end end describe :from_access_token_param do it 'returns token from access_token parameter' do request = double parameters: { access_token: 'some-token' } token = Token.from_access_token_param(request) expect(token).to eq('some-token') end end describe :from_bearer_param do it 'returns token from bearer_token parameter' do request = double parameters: { bearer_token: 'some-token' } token = Token.from_bearer_param(request) expect(token).to eq('some-token') end end describe :from_bearer_authorization do it 'returns token from capitalized authorization bearer' do request = double authorization: 'Bearer SomeToken' token = Token.from_bearer_authorization(request) expect(token).to eq('SomeToken') end it 'returns token from lowercased authorization bearer' do request = double authorization: 'bearer SomeToken' token = Token.from_bearer_authorization(request) expect(token).to eq('SomeToken') end it 'does not return token if authorization is not bearer' do request = double authorization: 'MAC SomeToken' token = Token.from_bearer_authorization(request) expect(token).to be_blank end end describe :from_basic_authorization do it 'returns token from capitalized authorization basic' do request = double authorization: "Basic #{Base64.encode64 'SomeToken:'}" token = Token.from_basic_authorization(request) expect(token).to eq('SomeToken') end it 'returns token from lowercased authorization basic' do request = double authorization: "basic #{Base64.encode64 'SomeToken:'}" token = Token.from_basic_authorization(request) expect(token).to eq('SomeToken') end it 'does not return token if authorization is not basic' do request = double authorization: "MAC #{Base64.encode64 'SomeToken:'}" token = Token.from_basic_authorization(request) expect(token).to be_blank end end describe :authenticate do let(:finder) { double :finder } it 'calls the finder if token was found' do token = ->(r) { 'token' } expect(AccessToken).to receive(:by_token).with('token') Token.authenticate double, token end end end end end doorkeeper-2.2.1/spec/lib/oauth/authorization_code_request_spec.rb0000644000076400007640000000441512544753400024540 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe AuthorizationCodeRequest do let(:server) do double :server, access_token_expires_in: 2.days, refresh_token_enabled?: false, custom_access_token_expires_in: ->(_app) { nil } end let(:grant) { FactoryGirl.create :access_grant } let(:client) { grant.application } subject do AuthorizationCodeRequest.new server, grant, client, redirect_uri: client.redirect_uri end it 'issues a new token for the client' do expect do subject.authorize end.to change { client.access_tokens.count }.by(1) end it "issues the token with same grant's scopes" do subject.authorize expect(Doorkeeper::AccessToken.last.scopes).to eq(grant.scopes) end it 'revokes the grant' do expect do subject.authorize end.to change { grant.reload.accessible? } end it 'requires the grant to be accessible' do grant.revoke subject.validate expect(subject.error).to eq(:invalid_grant) end it 'requires the grant' do subject.grant = nil subject.validate expect(subject.error).to eq(:invalid_grant) end it 'requires the client' do subject.client = nil subject.validate expect(subject.error).to eq(:invalid_client) end it 'requires the redirect_uri' do subject.redirect_uri = nil subject.validate expect(subject.error).to eq(:invalid_request) end it "matches the redirect_uri with grant's one" do subject.redirect_uri = 'http://other.com' subject.validate expect(subject.error).to eq(:invalid_grant) end it "matches the client with grant's one" do subject.client = FactoryGirl.create :application subject.validate expect(subject.error).to eq(:invalid_grant) end it 'skips token creation if there is a matching one' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: grant.resource_owner_id, scopes: grant.scopes.to_s) expect do subject.authorize end.to_not change { Doorkeeper::AccessToken.count } end end end doorkeeper-2.2.1/spec/lib/oauth/client/0000755000076400007640000000000012544753400017011 5ustar pravipravidoorkeeper-2.2.1/spec/lib/oauth/client/methods_spec.rb0000644000076400007640000000300212544753400022006 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/string' require 'doorkeeper/oauth/client' class Doorkeeper::OAuth::Client describe 'Methods' do let(:client_id) { 'some-uid' } let(:client_secret) { 'some-secret' } subject do Class.new do include Methods end.new end describe :from_params do it 'returns credentials from parameters when Authorization header is not available' do request = double parameters: { client_id: client_id, client_secret: client_secret } uid, secret = subject.from_params(request) expect(uid).to eq('some-uid') expect(secret).to eq('some-secret') end it 'is blank when there are no credentials' do request = double parameters: {} uid, secret = subject.from_params(request) expect(uid).to be_blank expect(secret).to be_blank end end describe :from_basic do let(:credentials) { Base64.encode64("#{client_id}:#{client_secret}") } it 'decodes the credentials' do request = double authorization: "Basic #{credentials}" uid, secret = subject.from_basic(request) expect(uid).to eq('some-uid') expect(secret).to eq('some-secret') end it 'is blank if Authorization is not Basic' do request = double authorization: "#{credentials}" uid, secret = subject.from_basic(request) expect(uid).to be_blank expect(secret).to be_blank end end end end doorkeeper-2.2.1/spec/lib/oauth/client/credentials_spec.rb0000644000076400007640000000275512544753400022656 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/string' require 'doorkeeper/oauth/client' class Doorkeeper::OAuth::Client describe Credentials do it 'is blank when any of the credentials is blank' do expect(Credentials.new(nil, 'something')).to be_blank expect(Credentials.new('something', nil)).to be_blank end describe :from_request do let(:request) { double.as_null_object } let(:method) do ->(_request) { return 'uid', 'secret' } end it 'accepts anything that responds to #call' do expect(method).to receive(:call).with(request) Credentials.from_request request, method end it 'delegates methods received as symbols to Credentials class' do expect(Credentials).to receive(:from_params).with(request) Credentials.from_request request, :from_params end it 'stops at the first credentials found' do not_called_method = double expect(not_called_method).not_to receive(:call) Credentials.from_request request, ->(_) {}, method, not_called_method end it 'returns new Credentials' do credentials = Credentials.from_request request, method expect(credentials).to be_a(Credentials) end it 'returns uid and secret from extractor method' do credentials = Credentials.from_request request, method expect(credentials.uid).to eq('uid') expect(credentials.secret).to eq('secret') end end end end doorkeeper-2.2.1/spec/lib/oauth/token_response_spec.rb0000644000076400007640000000451312544753400022133 0ustar pravipravirequire 'spec_helper' require 'doorkeeper/oauth/token_response' module Doorkeeper::OAuth describe TokenResponse do subject { TokenResponse.new(double.as_null_object) } it 'includes access token response headers' do headers = subject.headers expect(headers.fetch('Cache-Control')).to eq('no-store') expect(headers.fetch('Pragma')).to eq('no-cache') end it 'status is ok' do expect(subject.status).to eq(:ok) end describe '.body' do let(:access_token) do double :access_token, token: 'some-token', expires_in: '3600', expires_in_seconds: '300', scopes_string: 'two scopes', refresh_token: 'some-refresh-token', token_type: 'bearer', created_at: 0 end subject { TokenResponse.new(access_token).body } it 'includes :access_token' do expect(subject['access_token']).to eq('some-token') end it 'includes :token_type' do expect(subject['token_type']).to eq('bearer') end # expires_in_seconds is returned as `expires_in` in order to match # the OAuth spec (section 4.2.2) it 'includes :expires_in' do expect(subject['expires_in']).to eq('300') end it 'includes :scope' do expect(subject['scope']).to eq('two scopes') end it 'includes :refresh_token' do expect(subject['refresh_token']).to eq('some-refresh-token') end it 'includes :created_at' do expect(subject['created_at']).to eq(0) end end describe '.body filters out empty values' do let(:access_token) do double :access_token, token: 'some-token', expires_in_seconds: '', scopes_string: '', refresh_token: '', token_type: 'bearer', created_at: 0 end subject { TokenResponse.new(access_token).body } it 'includes :expires_in' do expect(subject['expires_in']).to be_nil end it 'includes :scope' do expect(subject['scope']).to be_nil end it 'includes :refresh_token' do expect(subject['refresh_token']).to be_nil end end end end doorkeeper-2.2.1/spec/lib/oauth/forbidden_token_response_spec.rb0000644000076400007640000000112312544753400024141 0ustar pravipravirequire 'spec_helper' require 'active_model' require 'doorkeeper' require 'doorkeeper/oauth/forbidden_token_response' module Doorkeeper::OAuth describe ForbiddenTokenResponse do describe '#name' do it { expect(subject.name).to eq(:invalid_scope) } end describe '#status' do it { expect(subject.status).to eq(:forbidden) } end describe :from_scopes do it 'should have a list of acceptable scopes' do response = ForbiddenTokenResponse.from_scopes(["public"]) expect(response.description).to include('public') end end end end doorkeeper-2.2.1/spec/lib/oauth/client_spec.rb0000644000076400007640000000256012544753400020353 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/string' require 'doorkeeper/oauth/client' module Doorkeeper::OAuth describe Client do describe :find do let(:method) { double } it 'finds the client via uid' do client = double expect(method).to receive(:call).with('uid').and_return(client) expect(Client.find('uid', method)).to be_a(Client) end it 'returns nil if client was not found' do expect(method).to receive(:call).with('uid').and_return(nil) expect(Client.find('uid', method)).to be_nil end end describe :authenticate do it 'returns the authenticated client via credentials' do credentials = Client::Credentials.new('some-uid', 'some-secret') authenticator = double expect(authenticator).to receive(:call).with('some-uid', 'some-secret').and_return(double) expect(Client.authenticate(credentials, authenticator)).to be_a(Client) end it 'returns nil if client was not authenticated' do credentials = Client::Credentials.new('some-uid', 'some-secret') authenticator = double expect(authenticator).to receive(:call).with('some-uid', 'some-secret').and_return(nil) expect(Client.authenticate(credentials, authenticator)).to be_nil end end end end doorkeeper-2.2.1/spec/lib/oauth/code_request_spec.rb0000644000076400007640000000211512544753400021553 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe CodeRequest do let(:pre_auth) do double( :pre_auth, client: double(:application, id: 9990), redirect_uri: 'http://tst.com/cb', scopes: nil, state: nil, error: nil, authorizable?: true ) end let(:owner) { double :owner, id: 8900 } subject do CodeRequest.new(pre_auth, owner) end it 'creates an access grant' do expect do subject.authorize end.to change { Doorkeeper::AccessGrant.count }.by(1) end it 'returns a code response' do expect(subject.authorize).to be_a(CodeResponse) end it 'does not create grant when not authorizable' do allow(pre_auth).to receive(:authorizable?).and_return(false) expect do subject.authorize end.to_not change { Doorkeeper::AccessGrant.count } end it 'returns a error response' do allow(pre_auth).to receive(:authorizable?).and_return(false) expect(subject.authorize).to be_a(ErrorResponse) end end end doorkeeper-2.2.1/spec/lib/oauth/error_spec.rb0000644000076400007640000000076512544753400020233 0ustar pravipravirequire 'spec_helper' require 'active_support/i18n' require 'doorkeeper/oauth/error' module Doorkeeper::OAuth describe Error do subject { Error.new(:some_error, :some_state) } it { should respond_to(:name) } it { should respond_to(:state) } describe :description do it 'is translated from translation messages' do expect(I18n).to receive(:translate).with(:some_error, scope: [:doorkeeper, :errors, :messages]) subject.description end end end end doorkeeper-2.2.1/spec/lib/oauth/scopes_spec.rb0000644000076400007640000000730212544753400020370 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/string' require 'doorkeeper/oauth/scopes' module Doorkeeper::OAuth describe Scopes do describe '#add' do it 'allows you to add scopes with symbols' do subject.add :public expect(subject.all).to eq(['public']) end it 'allows you to add scopes with strings' do subject.add 'public' expect(subject.all).to eq(['public']) end it 'do not add already included scopes' do subject.add :public subject.add :public expect(subject.all).to eq(['public']) end end describe '#exists' do before do subject.add :public end it 'returns true if scope with given name is present' do expect(subject.exists?('public')).to be_truthy end it 'returns false if scope with given name does not exist' do expect(subject.exists?('other')).to be_falsey end it 'handles symbols' do expect(subject.exists?(:public)).to be_truthy expect(subject.exists?(:other)).to be_falsey end end describe '.from_string' do let(:string) { 'public write' } subject { Scopes.from_string(string) } it { should be_a(Scopes) } describe '#all' do it 'should be an array of the expected scopes' do scopes_array = subject.all expect(scopes_array.size).to eq(2) expect(scopes_array).to include('public') expect(scopes_array).to include('write') end end end describe '#+' do it 'can add to another scope object' do scopes = Scopes.from_string('public') + Scopes.from_string('admin') expect(scopes.all).to eq(%w(public admin)) end it 'does not change the existing object' do origin = Scopes.from_string('public') new_scope = origin + Scopes.from_string('admin') expect(origin.to_s).to eq('public') end it 'raises an error if cannot handle addition' do expect do Scopes.from_string('public') + 'admin' end.to raise_error(NoMethodError) end end describe '#==' do it 'is equal to another set of scopes' do expect(Scopes.from_string('public')).to eq(Scopes.from_string('public')) end it 'is equal to another set of scopes with no particular order' do expect(Scopes.from_string('public write')).to eq(Scopes.from_string('write public')) end it 'differs from another set of scopes when scopes are not the same' do expect(Scopes.from_string('public write')).not_to eq(Scopes.from_string('write')) end end describe '#has_scopes?' do subject { Scopes.from_string('public admin') } it 'returns true when at least one scope is included' do expect(subject.has_scopes?(Scopes.from_string('public'))).to be_truthy end it 'returns true when all scopes are included' do expect(subject.has_scopes?(Scopes.from_string('public admin'))).to be_truthy end it 'is true if all scopes are included in any order' do expect(subject.has_scopes?(Scopes.from_string('admin public'))).to be_truthy end it 'is false if no scopes are included' do expect(subject.has_scopes?(Scopes.from_string('notexistent'))).to be_falsey end it 'returns false when any scope is not included' do expect(subject.has_scopes?(Scopes.from_string('public nope'))).to be_falsey end it 'is false if no scopes are included even for existing ones' do expect(subject.has_scopes?(Scopes.from_string('public admin notexistent'))).to be_falsey end end end end doorkeeper-2.2.1/spec/lib/oauth/client_credentials_request_spec.rb0000644000076400007640000000664712544753400024512 0ustar pravipravirequire 'spec_helper' require 'active_support/all' require 'active_model' require 'doorkeeper/oauth/client_credentials_request' module Doorkeeper::OAuth describe ClientCredentialsRequest do let(:server) do double( default_scopes: nil, custom_access_token_expires_in: ->(_app) { nil } ) end let(:application) { double :application, scopes: Scopes.from_string('') } let(:client) { double :client, application: application } let(:token_creator) { double :issuer, create: true, token: double } subject { ClientCredentialsRequest.new(server, client) } before do subject.issuer = token_creator end it 'issues an access token for the current client' do expect(token_creator).to receive(:create).with(client, nil) subject.authorize end it 'has successful response when issue was created' do subject.authorize expect(subject.response).to be_a(TokenResponse) end context 'if issue was not created' do before do subject.issuer = double create: false, error: :invalid end it 'has an error response' do subject.authorize expect(subject.response).to be_a(Doorkeeper::OAuth::ErrorResponse) end it 'delegates the error to issuer' do subject.authorize expect(subject.error).to eq(:invalid) end end context 'with scopes' do let(:default_scopes) { Doorkeeper::OAuth::Scopes.from_string('public email') } before do allow(server).to receive(:default_scopes).and_return(default_scopes) end it 'issues an access token with default scopes if none was requested' do expect(token_creator).to receive(:create).with(client, default_scopes) subject.authorize end it 'issues an access token with requested scopes' do subject = ClientCredentialsRequest.new(server, client, scope: 'email') subject.issuer = token_creator expect(token_creator).to receive(:create).with(client, Doorkeeper::OAuth::Scopes.from_string('email')) subject.authorize end end context 'with restricted client' do let(:default_scopes) do Doorkeeper::OAuth::Scopes.from_string('public email') end let(:server_scopes) do Doorkeeper::OAuth::Scopes.from_string('public email phone') end let(:client_scopes) do Doorkeeper::OAuth::Scopes.from_string('public phone') end before do allow(server).to receive(:default_scopes).and_return(default_scopes) allow(server).to receive(:scopes).and_return(server_scopes) allow(server).to receive(:access_token_expires_in).and_return(100) allow(application).to receive(:scopes).and_return(client_scopes) allow(client).to receive(:id).and_return(nil) end it 'delegates the error to issuer if no scope was requested' do subject = ClientCredentialsRequest.new(server, client) subject.authorize expect(subject.response).to be_a(Doorkeeper::OAuth::ErrorResponse) expect(subject.error).to eq(:invalid_scope) end it 'issues an access token with requested scopes' do subject = ClientCredentialsRequest.new(server, client, scope: 'phone') subject.authorize expect(subject.response).to be_a(Doorkeeper::OAuth::TokenResponse) expect(subject.response.token.scopes_string).to eq('phone') end end end end doorkeeper-2.2.1/spec/lib/oauth/client_credentials_integration_spec.rb0000644000076400007640000000136412544753400025334 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe ClientCredentialsRequest do let(:server) { Doorkeeper.configuration } context 'with a valid request' do let(:client) { FactoryGirl.create :application } it 'issues an access token' do request = ClientCredentialsRequest.new(server, client, {}) expect do request.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end end describe 'with an invalid request' do it 'does not issue an access token' do request = ClientCredentialsRequest.new(server, nil, {}) expect do request.authorize end.to_not change { Doorkeeper::AccessToken.count } end end end end doorkeeper-2.2.1/spec/lib/oauth/password_access_token_request_spec.rb0000644000076400007640000000542512544753400025233 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper::OAuth describe PasswordAccessTokenRequest do let(:server) do double( :server, default_scopes: Doorkeeper::OAuth::Scopes.new, access_token_expires_in: 2.hours, refresh_token_enabled?: false, custom_access_token_expires_in: ->(_app) { nil } ) end let(:credentials) { Client::Credentials.new(client.uid, client.secret) } let(:client) { FactoryGirl.create(:application) } let(:owner) { double :owner, id: 99 } subject do PasswordAccessTokenRequest.new(server, credentials, owner) end it 'issues a new token for the client' do expect do subject.authorize end.to change { client.access_tokens.count }.by(1) end it 'issues a new token without a client' do expect do subject.credentials = nil subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'does not issue a new token with an invalid client' do expect do subject.client = nil subject.authorize end.to_not change { Doorkeeper::AccessToken.count } expect(subject.error).to eq(:invalid_client) end it 'requires the owner' do subject.resource_owner = nil subject.validate expect(subject.error).to eq(:invalid_grant) end it 'optionally accepts the client' do subject.credentials = nil expect(subject).to be_valid end it 'creates token even when there is already one (default)' do FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id) expect do subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) end it 'skips token creation if there is already one' do allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id) expect do subject.authorize end.to_not change { Doorkeeper::AccessToken.count } end describe 'with scopes' do subject do PasswordAccessTokenRequest.new(server, client, owner, scope: 'public') end it 'validates the current scope' do allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('another')) subject.validate expect(subject.error).to eq(:invalid_scope) end it 'creates the token with scopes' do allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public')) expect do subject.authorize end.to change { Doorkeeper::AccessToken.count }.by(1) expect(Doorkeeper::AccessToken.last.scopes).to include('public') end end end end doorkeeper-2.2.1/spec/lib/models/0000755000076400007640000000000012544753400015676 5ustar pravipravidoorkeeper-2.2.1/spec/lib/models/revocable_spec.rb0000644000076400007640000000177712544753400021213 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/object/blank' require 'doorkeeper/models/concerns/revocable' describe 'Revocable' do subject do Class.new do include Doorkeeper::Models::Revocable end.new end describe :revoke do it 'updates :revoked_at attribute with current time' do clock = double now: double expect(subject).to receive(:update_attribute).with(:revoked_at, clock.now) subject.revoke(clock) end end describe :revoked? do it 'is revoked if :revoked_at has passed' do allow(subject).to receive(:revoked_at).and_return(DateTime.now - 1000) expect(subject).to be_revoked end it 'is not revoked if :revoked_at has not passed' do allow(subject).to receive(:revoked_at).and_return(DateTime.now + 1000) expect(subject).not_to be_revoked end it 'is not revoked if :revoked_at is not set' do allow(subject).to receive(:revoked_at).and_return(nil) expect(subject).not_to be_revoked end end end doorkeeper-2.2.1/spec/lib/models/expirable_spec.rb0000644000076400007640000000262612544753400021216 0ustar pravipravirequire 'spec_helper' require 'timecop' require 'active_support/time' require 'doorkeeper/models/concerns/expirable' describe 'Expirable' do subject do Class.new do include Doorkeeper::Models::Expirable end.new end before do allow(subject).to receive(:created_at).and_return(1.minute.ago) end describe :expired? do it 'is not expired if time has not passed' do allow(subject).to receive(:expires_in).and_return(2.minutes) expect(subject).not_to be_expired end it 'is expired if time has passed' do allow(subject).to receive(:expires_in).and_return(10.seconds) expect(subject).to be_expired end it 'is not expired if expires_in is not set' do allow(subject).to receive(:expires_in).and_return(nil) expect(subject).not_to be_expired end end describe :expires_in_seconds do it 'should return the amount of time remaining until the token is expired' do allow(subject).to receive(:expires_in).and_return(2.minutes) expect(subject.expires_in_seconds).to eq(60) end it 'should return 0 when expired' do allow(subject).to receive(:expires_in).and_return(30.seconds) expect(subject.expires_in_seconds).to eq(0) end it 'should return nil when expires_in is nil' do allow(subject).to receive(:expires_in).and_return(nil) expect(subject.expires_in_seconds).to be_nil end end end doorkeeper-2.2.1/spec/lib/models/scopes_spec.rb0000644000076400007640000000205712544753400020535 0ustar pravipravirequire 'spec_helper' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' require 'doorkeeper/oauth/scopes' require 'doorkeeper/models/concerns/scopes' describe 'Doorkeeper::Models::Scopes' do subject do Class.new(Hash) do include Doorkeeper::Models::Scopes end.new end before do subject[:scopes] = 'public admin' end describe :scopes do it 'is a `Scopes` class' do expect(subject.scopes).to be_a(Doorkeeper::OAuth::Scopes) end it 'includes scopes' do expect(subject.scopes).to include('public') end end describe :scopes_string do it 'is a `Scopes` class' do expect(subject.scopes_string).to eq('public admin') end end describe :includes_scope? do it 'should return true if at least one scope is included' do expect(subject.includes_scope?('public', 'private')).to be true end it 'should return false if no scopes are included' do expect(subject.includes_scope?('teacher', 'student')).to be false end end end doorkeeper-2.2.1/spec/lib/doorkeeper_spec.rb0000644000076400007640000000154212544753400020113 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper do describe 'authenticate' do let(:token) { double('Token') } let(:request) { double('ActionDispatch::Request') } before do allow(Doorkeeper::OAuth::Token).to receive(:authenticate). with(request, *token_strategies) { token } end context 'with specific access token strategies' do let(:token_strategies) { [:first_way, :second_way] } it 'authenticates the token from the request' do expect(Doorkeeper.authenticate(request, token_strategies)).to eq(token) end end context 'with default access token strategies' do let(:token_strategies) { Doorkeeper.configuration.access_token_methods } it 'authenticates the token from the request' do expect(Doorkeeper.authenticate(request)).to eq(token) end end end end doorkeeper-2.2.1/spec/controllers/0000755000076400007640000000000012544753400016213 5ustar pravipravidoorkeeper-2.2.1/spec/controllers/authorizations_controller_spec.rb0000644000076400007640000001372512544753400025110 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do include AuthorizationRequestHelper def fragments(param) fragment = URI.parse(response.location).fragment Rack::Utils.parse_query(fragment)[param] end def translated_error_message(key) I18n.translate key, scope: [:doorkeeper, :errors, :messages] end let(:client) { FactoryGirl.create :application } let(:user) { User.create!(name: 'Joe', password: 'sekret') } before do allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(["implicit"]) allow(controller).to receive(:current_resource_owner).and_return(user) end describe 'POST #create' do before do post :create, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri end it 'redirects after authorization' do expect(response).to be_redirect end it 'redirects to client redirect uri' do expect(response.location).to match(%r{^#{client.redirect_uri}}) end it 'includes access token in fragment' do expect(fragments('access_token')).to eq(Doorkeeper::AccessToken.first.token) end it 'includes token type in fragment' do expect(fragments('token_type')).to eq('bearer') end it 'includes token expiration in fragment' do expect(fragments('expires_in').to_i).to eq(2.hours.to_i) end it 'issues the token for the current client' do expect(Doorkeeper::AccessToken.first.application_id).to eq(client.id) end it 'issues the token for the current resource owner' do expect(Doorkeeper::AccessToken.first.resource_owner_id).to eq(user.id) end end describe 'POST #create with errors' do before do default_scopes_exist :public post :create, client_id: client.uid, response_type: 'token', scope: 'invalid', redirect_uri: client.redirect_uri end it 'redirects after authorization' do expect(response).to be_redirect end it 'redirects to client redirect uri' do expect(response.location).to match(%r{^#{client.redirect_uri}}) end it 'does not include access token in fragment' do expect(fragments('access_token')).to be_nil end it 'includes error in fragment' do expect(fragments('error')).to eq('invalid_scope') end it 'includes error description in fragment' do expect(fragments('error_description')).to eq(translated_error_message(:invalid_scope)) end it 'does not issue any access token' do expect(Doorkeeper::AccessToken.all).to be_empty end end describe 'POST #create with application already authorized' do it 'returns the existing access token in a fragment' end describe 'GET #new' do before do get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri end it 'renders new template' do expect(response).to render_template(:new) end end describe 'GET #new token request with native url and skip_authorization true' do before do allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do true end) client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob' get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri end it 'should redirect immediately' do expect(response).to be_redirect expect(response.location).to match(/oauth\/token\/info\?access_token=/) end it 'should not issue a grant' do expect(Doorkeeper::AccessGrant.count).to be 0 end it 'should issue a token' do expect(Doorkeeper::AccessToken.count).to be 1 end end describe 'GET #new code request with native url and skip_authorization true' do before do allow(Doorkeeper.configuration).to receive(:grant_flows). and_return(%w(authorization_code)) allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do true end) client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob' get :new, client_id: client.uid, response_type: 'code', redirect_uri: client.redirect_uri end it 'should redirect immediately' do expect(response).to be_redirect expect(response.location).to match(/oauth\/authorize\//) end it 'should issue a grant' do expect(Doorkeeper::AccessGrant.count).to be 1 end it 'should not issue a token' do expect(Doorkeeper::AccessToken.count).to be 0 end end describe 'GET #new with skip_authorization true' do before do allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do true end) get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri end it 'should redirect immediately' do expect(response).to be_redirect expect(response.location).to match(%r{^#{client.redirect_uri}}) end it 'should issue a token' do expect(Doorkeeper::AccessToken.count).to be 1 end it 'includes token type in fragment' do expect(fragments('token_type')).to eq('bearer') end it 'includes token expiration in fragment' do expect(fragments('expires_in').to_i).to eq(2.hours.to_i) end it 'issues the token for the current client' do expect(Doorkeeper::AccessToken.first.application_id).to eq(client.id) end it 'issues the token for the current resource owner' do expect(Doorkeeper::AccessToken.first.resource_owner_id).to eq(user.id) end end describe 'GET #new with errors' do before do default_scopes_exist :public get :new, an_invalid: 'request' end it 'does not redirect' do expect(response).to_not be_redirect end it 'renders error template' do expect(response).to render_template(:error) end it 'does not issue any token' do expect(Doorkeeper::AccessGrant.count).to eq 0 expect(Doorkeeper::AccessToken.count).to eq 0 end end end doorkeeper-2.2.1/spec/controllers/applications_controller_spec.rb0000644000076400007640000000345612544753400024513 0ustar pravipravirequire 'spec_helper_integration' module Doorkeeper describe ApplicationsController do context 'when admin is not authenticated' do before do allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(proc do redirect_to main_app.root_url end) end it 'redirects as set in Doorkeeper.authenticate_admin' do get :index expect(response).to redirect_to(controller.main_app.root_url) end it 'does not create application' do expect do post :create, doorkeeper_application: { name: 'Example', redirect_uri: 'https://example.com' } end.to_not change { Doorkeeper::Application.count } end end context 'when admin is authenticated' do before do allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(arg) { true }) end it 'creates application' do expect do post :create, doorkeeper_application: { name: 'Example', redirect_uri: 'https://example.com' } end.to change { Doorkeeper::Application.count }.by(1) expect(response).to be_redirect end it 'does not allow mass assignment of uid or secret' do application = FactoryGirl.create(:application) put :update, id: application.id, doorkeeper_application: { uid: '1A2B3C4D', secret: '1A2B3C4D' } expect(application.reload.uid).not_to eq '1A2B3C4D' end it 'updates application' do application = FactoryGirl.create(:application) put :update, id: application.id, doorkeeper_application: { name: 'Example', redirect_uri: 'https://example.com' } expect(application.reload.name).to eq 'Example' end end end end doorkeeper-2.2.1/spec/controllers/token_info_controller_spec.rb0000644000076400007640000000307112544753400024151 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper::TokenInfoController do describe 'when requesting tokeninfo with valid token' do let(:doorkeeper_token) { FactoryGirl.create(:access_token) } before(:each) do allow(controller).to receive(:doorkeeper_token) { doorkeeper_token } end def do_get get :show end describe 'successful request' do it 'responds with tokeninfo' do do_get expect(response.body).to eq(doorkeeper_token.to_json) end it 'responds with a 200 status' do do_get expect(response.status).to eq 200 end end describe 'invalid token response' do before(:each) do allow(controller).to receive(:doorkeeper_token).and_return(nil) end it 'responds with 401 when doorkeeper_token is not valid' do do_get expect(response.status).to eq 401 expect(response.headers['WWW-Authenticate']).to match(/^Bearer/) end it 'responds with 401 when doorkeeper_token is invalid, expired or revoked' do allow(controller).to receive(:doorkeeper_token).and_return(doorkeeper_token) allow(doorkeeper_token).to receive(:accessible?).and_return(false) do_get expect(response.status).to eq 401 expect(response.headers['WWW-Authenticate']).to match(/^Bearer/) end it 'responds body message for error' do do_get expect(response.body).to eq(Doorkeeper::OAuth::ErrorResponse.new(name: :invalid_request, status: :unauthorized).body.to_json) end end end end doorkeeper-2.2.1/spec/controllers/protected_resources_controller_spec.rb0000644000076400007640000001252312544753400026103 0ustar pravipravirequire 'spec_helper_integration' module ControllerActions def index render text: 'index' end def show render text: 'show' end end describe 'doorkeeper authorize filter' do context 'accepts token code specified as' do controller do before_filter :doorkeeper_authorize! def index render text: 'index' end end let(:token_string) { '1A2BC3' } let(:token) do double(Doorkeeper::AccessToken, acceptable?: true) end it 'access_token param' do expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) get :index, access_token: token_string end it 'bearer_token param' do expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) get :index, bearer_token: token_string end it 'Authorization header' do expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) request.env['HTTP_AUTHORIZATION'] = "Bearer #{token_string}" get :index end it 'different kind of Authorization header' do expect(Doorkeeper::AccessToken).not_to receive(:by_token) request.env['HTTP_AUTHORIZATION'] = "MAC #{token_string}" get :index end it 'does not change Authorization header value' do expect(Doorkeeper::AccessToken).to receive(:by_token).exactly(2).times.and_return(token) request.env['HTTP_AUTHORIZATION'] = "Bearer #{token_string}" get :index controller.send(:remove_instance_variable, :@_doorkeeper_token) get :index end end context 'defined for all actions' do controller do before_filter :doorkeeper_authorize! include ControllerActions end context 'with valid token', token: :valid do it 'allows into index action' do get :index, access_token: token_string expect(response).to be_success end it 'allows into show action' do get :show, id: '4', access_token: token_string expect(response).to be_success end end context 'with invalid token', token: :invalid do it 'does not allow into index action' do get :index, access_token: token_string expect(response.status).to eq 401 expect(response.header['WWW-Authenticate']).to match(/^Bearer/) end it 'does not allow into show action' do get :show, id: '4', access_token: token_string expect(response.status).to eq 401 expect(response.header['WWW-Authenticate']).to match(/^Bearer/) end end end context 'defined with scopes' do controller do before_filter -> { doorkeeper_authorize! :write } include ControllerActions end let(:token_string) { '1A2DUWE' } it 'allows if the token has particular scopes' do token = double(Doorkeeper::AccessToken, accessible?: true, scopes: %w(write public)) expect(token).to receive(:acceptable?).with([:write]).and_return(true) expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) get :index, access_token: token_string expect(response).to be_success end it 'does not allow if the token does not include given scope' do token = double(Doorkeeper::AccessToken, accessible?: true, scopes: ['public'], revoked?: false, expired?: false) expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token) expect(token).to receive(:acceptable?).with([:write]).and_return(false) get :index, access_token: token_string expect(response.status).to eq 403 expect(response.header).to_not include('WWW-Authenticate') end end context 'when custom unauthorized render options are configured' do controller do before_filter :doorkeeper_authorize! include ControllerActions end context 'with a JSON custom render', token: :invalid do before do expect(controller).to receive(:doorkeeper_unauthorized_render_options).and_return(json: ActiveSupport::JSON.encode(error: 'Unauthorized')) end it 'it renders a custom JSON response', token: :invalid do get :index, access_token: token_string expect(response.status).to eq 401 expect(response.content_type).to eq('application/json') expect(response.header['WWW-Authenticate']).to match(/^Bearer/) parsed_body = JSON.parse(response.body) expect(parsed_body).not_to be_nil expect(parsed_body['error']).to eq('Unauthorized') end end context 'with a text custom render', token: :invalid do before do expect(controller).to receive(:doorkeeper_unauthorized_render_options).and_return(text: 'Unauthorized') end it 'it renders a custom JSON response', token: :invalid do get :index, access_token: token_string expect(response.status).to eq 401 expect(response.content_type).to eq('text/html') expect(response.header['WWW-Authenticate']).to match(/^Bearer/) expect(response.body).to eq('Unauthorized') end end end context 'defined for all actions' do controller {} it 'it renders a custom JSON response' do expect do controller.class.doorkeeper_for end.to raise_error( Doorkeeper::Errors::DoorkeeperError, /`doorkeeper_for` no longer available/ ) end end end doorkeeper-2.2.1/spec/controllers/tokens_controller_spec.rb0000644000076400007640000000270712544753400023326 0ustar pravipravirequire 'spec_helper_integration' describe Doorkeeper::TokensController do describe 'when authorization has succeeded' do let :token do double(:token, authorize: true) end before do allow(controller).to receive(:token) { token } end it 'returns the authorization' do skip 'verify need of these specs' expect(token).to receive(:authorization) post :create end end describe 'when authorization has failed' do it 'returns the error response' do token = double(:token, authorize: false) allow(controller).to receive(:token) { token } post :create expect(response.status).to eq 401 expect(response.headers['WWW-Authenticate']).to match(/Bearer/) end end describe 'when revoke authorization has failed' do # http://tools.ietf.org/html/rfc7009#section-2.2 it 'returns no error response' do token = double(:token, authorize: false) allow(controller).to receive(:token) { token } post :revoke expect(response.status).to eq 200 end end describe 'authorize response memoization' do it "memoizes the result of the authorization" do strategy = double(:strategy, authorize: true) expect(strategy).to receive(:authorize).once allow(controller).to receive(:strategy) { strategy } allow(controller).to receive(:create) do controller.send :authorize_response end post :create end end end doorkeeper-2.2.1/.hound.yml0000644000076400007640000000015612544753400014633 0ustar pravipraviLineLength: Exclude: - spec/**/* StringLiterals: Enabled: false TrailingBlankLines: Enabled: true doorkeeper-2.2.1/.rspec0000644000076400007640000000001112544753400014020 0ustar pravipravi--colour doorkeeper-2.2.1/RELEASING.md0000644000076400007640000000112212544753400014542 0ustar pravipravi# Releasing doorkeeper 1. Update `lib/doorkeeper/version.rb` file accordingly. 2. Update `NEWS.md` to reflect the changes since last release. 3. Commit changes. There shouldn’t be code changes, and thus CI doesn’t need to run, you can then add “[ci skip]” to the commit message. 4. Tag the release: `git tag vVERSION` 5. Push changes: `git push --tags` 6. Build and publish the gem: ```bash gem build doorkeeper.gemspec gem push doorkeeper-*.gem ``` 7. Announce the new release, making sure to say “thank you” to the contributors who helped shape this version! doorkeeper-2.2.1/CONTRIBUTING.md0000644000076400007640000000175412544753400015153 0ustar pravipravi# Contributing We love pull requests from everyone. By participating in this project, you agree to abide by the thoughtbot [code of conduct]. [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct Fork, then clone the repo: git clone git@github.com:your-username/doorkeeper.git Set up Ruby dependencies via Bundler bundle install Make sure the tests pass: rake Make your change. Write tests. Follow our [style guide][style]. Make the tests pass: [style]: https://github.com/thoughtbot/guides/tree/master/style rake Write a [good commit message][commit]. Push to your fork. [Submit a pull request][pr]. [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [pr]: https://github.com/doorkeeper-gem/doorkeeper/compare/ If [Hound] catches style violations, fix them. [hound]: https://houndci.com Wait for us. We try to at least comment on pull requests within one business day. We may suggest changes. Thank you for your contribution! doorkeeper-2.2.1/.travis.yml0000644000076400007640000000127712544753400015033 0ustar pravipravilanguage: ruby sudo: false cache: bundler rvm: - 2.0 - 2.1 - 2.2 env: - rails=3.2.0 - rails=4.1.0 - rails=4.2.0 gemfile: - Gemfile - gemfiles/Gemfile.mongoid2.rb - gemfiles/Gemfile.mongoid3.rb - gemfiles/Gemfile.mongoid4.rb - gemfiles/Gemfile.mongo_mapper.rb services: - mongodb matrix: exclude: - env: rails=3.2.0 rvm: 2.2 - gemfile: gemfiles/Gemfile.mongoid2.rb env: rails=4.1.0 - gemfile: gemfiles/Gemfile.mongoid2.rb env: rails=4.2.0 - gemfile: gemfiles/Gemfile.mongoid3.rb env: rails=4.1.0 - gemfile: gemfiles/Gemfile.mongoid3.rb env: rails=4.2.0 - gemfile: gemfiles/Gemfile.mongoid4.rb env: rails=3.2.0 doorkeeper-2.2.1/vendor/0000755000076400007640000000000012544753400014210 5ustar pravipravidoorkeeper-2.2.1/vendor/assets/0000755000076400007640000000000012544753400015512 5ustar pravipravidoorkeeper-2.2.1/vendor/assets/stylesheets/0000755000076400007640000000000012544753400020066 5ustar pravipravidoorkeeper-2.2.1/vendor/assets/stylesheets/doorkeeper/0000755000076400007640000000000012544753400022225 5ustar pravipravidoorkeeper-2.2.1/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css0000755000076400007640000030672112544753400025552 0ustar pravipravi/*! * Bootstrap v3.1.0 (http://getbootstrap.com) * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.428571429;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=date]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.428571429;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../../../../../../../Downloads/bootstrap-3.1.0/dist/fonts/glyphicons-halflings-regular.eot);src:url(../../../../../../../Downloads/bootstrap-3.1.0/dist/fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../../../../../../../Downloads/bootstrap-3.1.0/dist/fonts/glyphicons-halflings-regular.woff) format('woff'),url(../../../../../../../Downloads/bootstrap-3.1.0/dist/fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../../../../../../../Downloads/bootstrap-3.1.0/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.428571429;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group .list-group-item:first-child{border-top:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel>.list-group:first-child .list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tfoot>tr:first-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tfoot>tr:first-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>td{border-top:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.428571429px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top .arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right .arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom .arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left .arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5) 0),color-stop(rgba(0,0,0,.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001) 0),color-stop(rgba(0,0,0,.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}@media print{.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} doorkeeper-2.2.1/config/0000755000076400007640000000000012544753400014160 5ustar pravipravidoorkeeper-2.2.1/config/locales/0000755000076400007640000000000012544753400015602 5ustar pravipravidoorkeeper-2.2.1/config/locales/en.yml0000644000076400007640000001251712544753400016735 0ustar pravipravien: activerecord: attributes: doorkeeper/application: name: 'Name' redirect_uri: 'Redirect URI' errors: models: doorkeeper/application: attributes: redirect_uri: fragment_present: 'cannot contain a fragment.' invalid_uri: 'must be a valid URI.' relative_uri: 'must be an absolute URI.' secured_uri: 'must be an HTTPS/SSL URI.' mongoid: attributes: doorkeeper/application: name: 'Name' redirect_uri: 'Redirect URI' errors: models: doorkeeper/application: attributes: redirect_uri: fragment_present: 'cannot contain a fragment.' invalid_uri: 'must be a valid URI.' relative_uri: 'must be an absolute URI.' secured_uri: 'must be an HTTPS/SSL URI.' mongo_mapper: attributes: doorkeeper/application: name: 'Name' redirect_uri: 'Redirect URI' errors: models: doorkeeper/application: attributes: redirect_uri: fragment_present: 'cannot contain a fragment.' invalid_uri: 'must be a valid URI.' relative_uri: 'must be an absolute URI.' secured_uri: 'must be an HTTPS/SSL URI.' doorkeeper: applications: confirmations: destroy: 'Are you sure?' buttons: edit: 'Edit' destroy: 'Destroy' submit: 'Submit' cancel: 'Cancel' authorize: 'Authorize' form: error: 'Whoops! Check your form for possible errors' help: redirect_uri: 'Use one line per URI' native_redirect_uri: 'Use %{native_redirect_uri} for local tests' edit: title: 'Edit application' index: title: 'Your applications' new: 'New Application' name: 'Name' callback_url: 'Callback URL' new: title: 'New Application' show: title: 'Application: %{name}' application_id: 'Application Id' secret: 'Secret' callback_urls: 'Callback urls' actions: 'Actions' authorizations: buttons: authorize: 'Authorize' deny: 'Deny' error: title: 'An error has occurred' new: title: 'Authorize required' prompt: 'Authorize %{client_name} to use your account?' able_to: 'This application will be able to' show: title: 'Authorization code' authorized_applications: confirmations: revoke: 'Are you sure?' buttons: revoke: 'Revoke' index: title: 'Your authorized applications' application: 'Application' created_at: 'Created At' date_format: '%Y-%m-%d %H:%M:%S' errors: messages: # Common error messages invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.' invalid_redirect_uri: 'The redirect uri included is not valid.' unauthorized_client: 'The client is not authorized to perform this request using this method.' access_denied: 'The resource owner or authorization server denied the request.' invalid_scope: 'The requested scope is invalid, unknown, or malformed.' server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.' #configuration error messages credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.' resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.' # Access grant errors unsupported_response_type: 'The authorization server does not support this response type.' # Access token errors invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.' invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.' unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.' # Password Access token errors invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found' invalid_token: revoked: "The access token was revoked" expired: "The access token expired" unknown: "The access token is invalid" flash: applications: create: notice: 'Application created.' destroy: notice: 'Application deleted.' update: notice: 'Application updated.' authorized_applications: destroy: notice: 'Application revoked.' layouts: admin: nav: oauth2_provider: 'OAuth2 Provider' applications: 'Applications' application: title: 'OAuth authorize required'doorkeeper-2.2.1/doorkeeper.gemspec0000644000076400007640000000233712544753400016424 0ustar pravipravi$:.push File.expand_path("../lib", __FILE__) require "doorkeeper/version" Gem::Specification.new do |s| s.name = "doorkeeper" s.version = Doorkeeper::VERSION s.authors = ["Felipe Elias Philipp", "Tute Costa"] s.email = %w(tutecosta@gmail.com) s.homepage = "https://github.com/doorkeeper-gem/doorkeeper" s.summary = "OAuth 2 provider for Rails and Grape" s.description = "Doorkeeper is an OAuth 2 provider for Rails and Grape." s.license = 'MIT' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- spec/*`.split("\n") s.require_paths = ["lib"] s.add_dependency "railties", ">= 3.2" s.add_development_dependency "sqlite3", "~> 1.3.5" s.add_development_dependency "rspec-rails", "~> 3.2.0" s.add_development_dependency "capybara", "~> 2.3.0" s.add_development_dependency "generator_spec", "~> 0.9.0" s.add_development_dependency "factory_girl", "~> 4.5.0" s.add_development_dependency "timecop", "~> 0.7.0" s.add_development_dependency "database_cleaner", "~> 1.3.0" s.add_development_dependency "rspec-activemodel-mocks", "~> 1.0.0" s.add_development_dependency "bcrypt-ruby", "~> 3.0.1" s.add_development_dependency "pry", "~> 0.10.0" end doorkeeper-2.2.1/README.md0000644000076400007640000003156312544753400014202 0ustar pravipravi# Doorkeeper - awesome oauth provider for your Rails app. [![Build Status](https://travis-ci.org/doorkeeper-gem/doorkeeper.svg?branch=master)](https://travis-ci.org/doorkeeper-gem/doorkeeper) [![Dependency Status](https://gemnasium.com/applicake/doorkeeper.svg?travis)](https://gemnasium.com/applicake/doorkeeper) [![Code Climate](https://codeclimate.com/github/applicake/doorkeeper.svg)](https://codeclimate.com/github/applicake/doorkeeper) [![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper) Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider functionality to your Rails or Grape application. [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567 ## Documentation valid for `master` branch Please check the documentation for the version of doorkeeper you are using in: https://github.com/doorkeeper-gem/doorkeeper/releases. ## Table of Contents - [Useful links](#useful-links) - [Requirements](#requirements) - [Installation](#installation) - [Configuration](#configuration) - [Active Record](#active-record) - [Mongoid / MongoMapper](#mongoid--mongomapper) - [Mongoid indexes](#mongoid-indexes) - [MongoMapper indexes](#mongomapper-indexes) - [Routes](#routes) - [Authenticating](#authenticating) - [Internationalization (I18n)](#internationalization-i18n) - [Protecting resources with OAuth (a.k.a your API endpoint)](#protecting-resources-with-oauth-aka-your-api-endpoint) - [Protect your API with OAuth when using Grape](#protect-your-api-with-oauth-when-using-grape) - [Route Constraints and other integrations](#route-constraints-and-other-integrations) - [Access Token Scopes](#access-token-scopes) - [Custom Access Token Generator](#custom-access-token-generator) - [Authenticated resource owner](#authenticated-resource-owner) - [Applications list](#applications-list) - [Other customizations](#other-customizations) - [Upgrading](#upgrading) - [Development](#development) - [Contributing](#contributing) - [Other resources](#other-resources) - [Wiki](#wiki) - [Live demo](#live-demo) - [Screencast](#screencast) - [Client applications](#client-applications) - [Contributors](#contributors) - [IETF Standards](#ietf-standards) - [License](#license) ## Useful links - For documentation, please check out our [wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki) - For general questions, please post it in [stack overflow](http://stackoverflow.com/questions/tagged/doorkeeper) ## Requirements - Ruby >= 2.0.0 - Rails >= 3.2 - ORM ActiveRecord, Mongoid, MongoMapper ## Installation Put this in your Gemfile: ``` ruby gem 'doorkeeper' ``` Run the installation generator with: rails generate doorkeeper:install This will install the doorkeeper initializer into `config/initializers/doorkeeper.rb`. ## Configuration ### Active Record By default doorkeeper is configured to use active record, so to start you have to generate the migration tables: rails generate doorkeeper:migration Don't forget to run the migration with: rake db:migrate ### Mongoid / MongoMapper Doorkeeper currently supports MongoMapper, Mongoid 2 and 3. To start using it, you have to set the `orm` configuration: ``` ruby Doorkeeper.configure do orm :mongoid2 # or :mongoid3, :mongoid4, :mongo_mapper end ``` #### Mongoid indexes Make sure you create indexes for doorkeeper models. You can do this either by running `rake db:mongoid:create_indexes` or (if you're using Mongoid 2) by adding `autocreate_indexes: true` to your `config/mongoid.yml` #### MongoMapper indexes Generate the `db/indexes.rb` file and create indexes for the doorkeeper models: rails generate doorkeeper:mongo_mapper:indexes rake db:index ### Routes The installation script will also automatically add the Doorkeeper routes into your app, like this: ``` ruby Rails.application.routes.draw do use_doorkeeper # your routes end ``` This will mount following routes: GET /oauth/authorize/:code GET /oauth/authorize POST /oauth/authorize PUT /oauth/authorize DELETE /oauth/authorize POST /oauth/token POST /oauth/revoke resources /oauth/applications GET /oauth/authorized_applications DELETE /oauth/authorized_applications/:id GET /oauth/token/info For more information on how to customize routes, check out [this page on the wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes). ### Authenticating You need to configure Doorkeeper in order to provide `resource_owner` model and authentication block `initializers/doorkeeper.rb` ``` ruby Doorkeeper.configure do resource_owner_authenticator do User.find_by_id(session[:current_user_id]) || redirect_to(login_url) end end ``` This code is run in the context of your application so you have access to your models, session or routes helpers. However, since this code is not run in the context of your application's `ApplicationController` it doesn't have access to the methods defined over there. You may want to check other ways of authentication [here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Authenticating-using-Clearance-or-DIY). ### Internationalization (I18n) See language files in [the I18n repository](https://github.com/doorkeeper-gem/doorkeeper-i18n). ## Protecting resources with OAuth (a.k.a your API endpoint) To protect your API with OAuth, you just need to setup `before_action`s specifying the actions you want to protect. For example: ``` ruby class Api::V1::ProductsController < Api::V1::ApiController before_action :doorkeeper_authorize! # Require access token for all actions # your actions end ``` You can pass any option `before_action` accepts, such as `if`, `only`, `except`, and others. ### Protect your API with OAuth when using Grape As of [PR 567] doorkeeper has helpers for Grape. One of them is `doorkeeper_authorize!` and can be used in a similar way as an example above. Note that you have to use `require 'doorkeeper/grape/helpers'` and `helpers Doorkeeper::Grape::Helpers`. For more information about integration with Grape see the [Wiki]. [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567 [Wiki]: https://github.com/doorkeeper-gem/doorkeeper/wiki/Grape-Integration ``` ruby require 'doorkeeper/grape/helpers' module API module V1 class Users < Grape::API helpers Doorkeeper::Grape::Helpers before do doorkeeper_authorize! end # ... end end end ``` ### Route Constraints and other integrations You can leverage the `Doorkeeper.authenticate` facade to easily extract a `Doorkeeper::OAuth::Token` based on the current request. You can then ensure that token is still good, find its associated `#resource_owner_id`, etc. ```ruby module Constraint class Authenticated def matches?(request) token = Doorkeeper.authenticate(request) token && token.accessible? end end end ``` For more information about integration and other integrations, check out [the related wiki page](https://github.com/doorkeeper-gem/doorkeeper/wiki/ActionController::Metal-with-doorkeeper). ### Access Token Scopes You can also require the access token to have specific scopes in certain actions: First configure the scopes in `initializers/doorkeeper.rb` ```ruby Doorkeeper.configure do default_scopes :public # if no scope was requested, this will be the default optional_scopes :admin, :write end ``` And in your controllers: ```ruby class Api::V1::ProductsController < Api::V1::ApiController before_action -> { doorkeeper_authorize! :public }, only: :index before_action only: [:create, :update, :destroy] do doorkeeper_authorize! :admin, :write end end ``` Please note that there is a logical OR between multiple required scopes. In above example, `doorkeeper_authorize! :admin, :write` means that the access token is required to have either `:admin` scope or `:write` scope, but not need have both of them. If want to require the access token to have multiple scopes at the same time, use multiple `doorkeeper_authorize!`, for example: ```ruby class Api::V1::ProductsController < Api::V1::ApiController before_action -> { doorkeeper_authorize! :public }, only: :index before_action only: [:create, :update, :destroy] do doorkeeper_authorize! :admin doorkeeper_authorize! :write end end ``` In above example, a client can call `:create` action only if its access token have both `:admin` and `:write` scopes. ### Custom Access Token Generator By default a 32 bit access token will be generated. If you require a custom token, such as [JWT](http://jwt.io), specify an object that responds to `.generate(options = {})` and returns a string to be used as the token. ```ruby Doorkeeper.configure do access_token_generator "Doorkeeper::JWT" end ``` JWT token support is available with [Doorkeeper-JWT](https://github.com/chriswarren/doorkeeper-jwt). ### Authenticated resource owner If you want to return data based on the current resource owner, in other words, the access token owner, you may want to define a method in your controller that returns the resource owner instance: ``` ruby class Api::V1::CredentialsController < Api::V1::ApiController before_action :doorkeeper_authorize! respond_to :json # GET /me.json def me respond_with current_resource_owner end private # Find the user that owns the access token def current_resource_owner User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token end end ``` In this example, we're returning the credentials (`me.json`) of the access token owner. ### Applications list By default, the applications list (`/oauth/applications`) is public available. To protect the endpoint you should uncomment these lines: ```ruby # config/initializers/doorkeeper.rb Doorkeeper.configure do admin_authenticator do |routes| Admin.find_by_id(session[:admin_id]) || redirect_to(routes.new_admin_session_url) end end ``` The logic is the same as the `resource_owner_authenticator` block. **Note:** since the application list is just a scaffold, it's recommended to either customize the controller used by the list or skip the controller at all. For more information see the page [in the wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes). ## Other customizations - [Associate users to OAuth applications (ownership)](https://github.com/doorkeeper-gem/doorkeeper/wiki/Associate-users-to-OAuth-applications-%28ownership%29) - [CORS - Cross Origin Resource Sharing](https://github.com/doorkeeper-gem/doorkeeper/wiki/%5BCORS%5D-Cross-Origin-Resource-Sharing) ## Upgrading If you want to upgrade doorkeeper to a new version, check out the [upgrading notes](https://github.com/doorkeeper-gem/doorkeeper/wiki/Migration-from-old-versions) and take a look at the [changelog](https://github.com/doorkeeper-gem/doorkeeper/blob/master/CHANGELOG.md). ## Development To run the local engine server: ``` bundle install bundle exec rails server ```` By default, it uses the latest Rails version with ActiveRecord. To run the tests with a specific ORM and Rails version: ``` rails=4.2.0 orm=active_record bundle exec rake ``` Or you might prefer to run `script/run_all` to integrate against all ORMs. ## Contributing Want to contribute and don't know where to start? Check out [features we're missing](https://github.com/doorkeeper-gem/doorkeeper/wiki/Supported-Features), create [example apps](https://github.com/doorkeeper-gem/doorkeeper/wiki/Example-Applications), integrate the gem with your app and let us know! Also, check out our [contributing guidelines page](https://github.com/doorkeeper-gem/doorkeeper/wiki/Contributing). ## Other resources ### Wiki You can find everything about doorkeeper in our [wiki here](https://github.com/doorkeeper-gem/doorkeeper/wiki). ### Live demo Check out this [live demo](http://doorkeeper-provider.herokuapp.com) hosted on heroku. For more demos check out [the wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Example-Applications). ### Screencast Check out this screencast from [railscasts.com](http://railscasts.com/): [#353 OAuth with Doorkeeper](http://railscasts.com/episodes/353-oauth-with-doorkeeper) ### Client applications After you set up the provider, you may want to create a client application to test the integration. Check out these [client examples](https://github.com/doorkeeper-gem/doorkeeper/wiki/Example-Applications) in our wiki or follow this [tutorial here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Testing-your-provider-with-OAuth2-gem). ### Contributors Thanks to all our [awesome contributors](https://github.com/doorkeeper-gem/doorkeeper/contributors)! ### IETF Standards * [The OAuth 2.0 Authorization Framework](http://tools.ietf.org/html/rfc6749) * [OAuth 2.0 Threat Model and Security Considerations](http://tools.ietf.org/html/rfc6819) ### License MIT License. Copyright 2011 Applicake. [http://applicake.com](http://applicake.com) doorkeeper-2.2.1/CHANGELOG.md0000644000076400007640000000012512544753400014522 0ustar pravipraviMoved to [NEWS.md](https://github.com/doorkeeper-gem/doorkeeper/blob/master/NEWS.md) doorkeeper-2.2.1/app/0000755000076400007640000000000012544753400013473 5ustar pravipravidoorkeeper-2.2.1/app/assets/0000755000076400007640000000000012544753400014775 5ustar pravipravidoorkeeper-2.2.1/app/assets/stylesheets/0000755000076400007640000000000012544753400017351 5ustar pravipravidoorkeeper-2.2.1/app/assets/stylesheets/doorkeeper/0000755000076400007640000000000012544753400021510 5ustar pravipravidoorkeeper-2.2.1/app/assets/stylesheets/doorkeeper/application.css0000644000076400007640000000162012544753400024524 0ustar pravipravi/* *= require doorkeeper/bootstrap.min * *= require_self *= require_tree . */ body { background-color: #eee; font-size: 14px; } #container { background-color: #fff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); box-shadow: 0 3px 20px rgba(0, 0, 0, 0.3); margin: 2em auto; max-width: 600px; outline: 0; padding: 1em; width: 80%; } .page-header { margin-top: 20px; } #oauth-permissions { width: 260px; } .actions { border-top: 1px solid #eee; margin-top: 1em; padding-top: 9px; } .actions > form > .btn { margin-top: 5px; } .separator { color: #eee; padding: 0 .5em; } .inline_block { display: inline-block; } #oauth { margin-bottom: 1em; } #oauth > .btn { width: 7em; } td { vertical-align: middle !important; } doorkeeper-2.2.1/app/assets/stylesheets/doorkeeper/admin/0000755000076400007640000000000012544753400022600 5ustar pravipravidoorkeeper-2.2.1/app/assets/stylesheets/doorkeeper/admin/application.css0000644000076400007640000000024012544753400025611 0ustar pravipravi/* *= require doorkeeper/bootstrap.min * *= require_self *= require_tree . */ body { padding-top: 60px; } td { vertical-align: middle !important; } doorkeeper-2.2.1/app/helpers/0000755000076400007640000000000012544753400015135 5ustar pravipravidoorkeeper-2.2.1/app/helpers/doorkeeper/0000755000076400007640000000000012544753400017274 5ustar pravipravidoorkeeper-2.2.1/app/helpers/doorkeeper/dashboard_helper.rb0000644000076400007640000000066712544753400023120 0ustar pravipravimodule Doorkeeper::DashboardHelper def doorkeeper_errors_for(object, method) if object.errors[method].present? object.errors[method].map do |msg| content_tag(:span, class: 'help-block') do msg.capitalize end end.reduce(&:join).html_safe end end def doorkeeper_submit_path(application) application.persisted? ? oauth_application_path(application) : oauth_applications_path end end doorkeeper-2.2.1/app/views/0000755000076400007640000000000012544753400014630 5ustar pravipravidoorkeeper-2.2.1/app/views/layouts/0000755000076400007640000000000012544753400016330 5ustar pravipravidoorkeeper-2.2.1/app/views/layouts/doorkeeper/0000755000076400007640000000000012544753400020467 5ustar pravipravidoorkeeper-2.2.1/app/views/layouts/doorkeeper/admin.html.erb0000644000076400007640000000177612544753400023227 0ustar pravipravi Doorkeeper <%= stylesheet_link_tag "doorkeeper/admin/application" %> <%= csrf_meta_tags %>
<%- if flash[:notice].present? %>
<%= flash[:notice] %>
<% end -%> <%= yield %>
doorkeeper-2.2.1/app/views/layouts/doorkeeper/application.html.erb0000644000076400007640000000101712544753400024426 0ustar pravipravi <%= t('doorkeeper.layouts.application.title') %> <%= stylesheet_link_tag "doorkeeper/application" %> <%= csrf_meta_tags %>
<%- if flash[:notice].present? %>
<%= flash[:notice] %>
<% end -%> <%= yield %>
doorkeeper-2.2.1/app/views/doorkeeper/0000755000076400007640000000000012544753400016767 5ustar pravipravidoorkeeper-2.2.1/app/views/doorkeeper/authorized_applications/0000755000076400007640000000000012544753400023713 5ustar pravipravidoorkeeper-2.2.1/app/views/doorkeeper/authorized_applications/index.html.erb0000644000076400007640000000136412544753400026463 0ustar pravipravi
<% @applications.each do |application| %> <% end %>
<%= t('doorkeeper.authorized_applications.index.application') %> <%= t('doorkeeper.authorized_applications.index.created_at') %>
<%= application.name %> <%= application.created_at.strftime(t('doorkeeper.authorized_applications.index.date_format')) %> <%= render 'delete_form', application: application %>
doorkeeper-2.2.1/app/views/doorkeeper/authorized_applications/_delete_form.html.erb0000644000076400007640000000055512544753400030001 0ustar pravipravi<%- submit_btn_css ||= 'btn btn-link' %> <%= form_tag oauth_authorized_application_path(application) do %> <%= submit_tag t('doorkeeper.authorized_applications.buttons.revoke'), onclick: "return confirm('#{ t('doorkeeper.authorized_applications.confirmations.revoke') }')", class: submit_btn_css %> <% end %> doorkeeper-2.2.1/app/views/doorkeeper/applications/0000755000076400007640000000000012544753400021455 5ustar pravipravidoorkeeper-2.2.1/app/views/doorkeeper/applications/show.html.erb0000644000076400007640000000217412544753400024076 0ustar pravipravi

<%= t('.application_id') %>:

<%= @application.uid %>

<%= t('.secret') %>:

<%= @application.secret %>

<%= t('.callback_urls') %>:

<% @application.redirect_uri.split.each do |uri| %> <% end %>
<%= uri %> <%= link_to t('doorkeeper.applications.buttons.authorize'), oauth_authorization_path(client_id: @application.uid, redirect_uri: uri, response_type: 'code'), class: 'btn btn-success', target: '_blank' %>

<%= t('.actions') %>

<%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(@application), class: 'btn btn-primary' %>

<%= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger' %>

doorkeeper-2.2.1/app/views/doorkeeper/applications/index.html.erb0000644000076400007640000000144212544753400024222 0ustar pravipravi

<%= link_to t('.new'), new_oauth_application_path, class: 'btn btn-success' %>

<% @applications.each do |application| %> <% end %>
<%= t('.name') %> <%= t('.callback_url') %>
<%= link_to application.name, oauth_application_path(application) %> <%= application.redirect_uri %> <%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %> <%= render 'delete_form', application: application %>
doorkeeper-2.2.1/app/views/doorkeeper/applications/_form.html.erb0000644000076400007640000000321012544753400024210 0ustar pravipravi<%= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f| %> <% if application.errors.any? %>

<%= t('doorkeeper.applications.form.error') %>

<% end %> <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do %> <%= f.label :name, class: 'col-sm-2 control-label' %>
<%= f.text_field :name, class: 'form-control' %> <%= doorkeeper_errors_for application, :name %>
<% end %> <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do %> <%= f.label :redirect_uri, class: 'col-sm-2 control-label' %>
<%= f.text_area :redirect_uri, class: 'form-control' %> <%= doorkeeper_errors_for application, :redirect_uri %> <%= t('doorkeeper.applications.help.redirect_uri') %> <% if Doorkeeper.configuration.native_redirect_uri %> <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: "#{ Doorkeeper.configuration.native_redirect_uri }") %> <% end %>
<% end %>
<%= f.submit t('doorkeeper.applications.buttons.submit'), class: "btn btn-primary" %> <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, :class => "btn btn-default" %>
<% end %> doorkeeper-2.2.1/app/views/doorkeeper/applications/_delete_form.html.erb0000644000076400007640000000051612544753400025540 0ustar pravipravi<%- submit_btn_css ||= 'btn btn-link' %> <%= form_tag oauth_application_path(application) do %> <%= submit_tag t('doorkeeper.applications.buttons.destroy'), onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')", class: submit_btn_css %> <% end %> doorkeeper-2.2.1/app/views/doorkeeper/applications/edit.html.erb0000644000076400007640000000016012544753400024034 0ustar pravipravi <%= render 'form', application: @application %> doorkeeper-2.2.1/app/views/doorkeeper/applications/new.html.erb0000644000076400007640000000016012544753400023700 0ustar pravipravi <%= render 'form', application: @application %> doorkeeper-2.2.1/app/views/doorkeeper/authorizations/0000755000076400007640000000000012544753400022052 5ustar pravipravidoorkeeper-2.2.1/app/views/doorkeeper/authorizations/show.html.erb0000644000076400007640000000023612544753400024470 0ustar pravipravi
<%= params[:code] %>
doorkeeper-2.2.1/app/views/doorkeeper/authorizations/error.html.erb0000644000076400007640000000030012544753400024631 0ustar pravipravi
<%= @pre_auth.error_response.body[:error_description] %>
doorkeeper-2.2.1/app/views/doorkeeper/authorizations/new.html.erb0000644000076400007640000000304112544753400024276 0ustar pravipravi

<%= raw t('.prompt', client_name: "#{ @pre_auth.client.name }") %>

<% if @pre_auth.scopes %>

<%= t('.able_to') %>:

<% end %>
<%= form_tag oauth_authorization_path, method: :post do %> <%= hidden_field_tag :client_id, @pre_auth.client.uid %> <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %> <%= hidden_field_tag :state, @pre_auth.state %> <%= hidden_field_tag :response_type, @pre_auth.response_type %> <%= hidden_field_tag :scope, @pre_auth.scope %> <%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %> <% end %> <%= form_tag oauth_authorization_path, method: :delete do %> <%= hidden_field_tag :client_id, @pre_auth.client.uid %> <%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %> <%= hidden_field_tag :state, @pre_auth.state %> <%= hidden_field_tag :response_type, @pre_auth.response_type %> <%= hidden_field_tag :scope, @pre_auth.scope %> <%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %> <% end %>
doorkeeper-2.2.1/app/validators/0000755000076400007640000000000012544753400015643 5ustar pravipravidoorkeeper-2.2.1/app/validators/redirect_uri_validator.rb0000644000076400007640000000200312544753400022710 0ustar pravipravirequire 'uri' class RedirectUriValidator < ActiveModel::EachValidator def self.native_redirect_uri Doorkeeper.configuration.native_redirect_uri end def validate_each(record, attribute, value) if value.blank? record.errors.add(attribute, :blank) else value.split.each do |val| uri = ::URI.parse(val) return if native_redirect_uri?(uri) record.errors.add(attribute, :fragment_present) unless uri.fragment.nil? record.errors.add(attribute, :relative_uri) if uri.scheme.nil? || uri.host.nil? record.errors.add(attribute, :secured_uri) if invalid_ssl_uri?(uri) end end rescue URI::InvalidURIError record.errors.add(attribute, :invalid_uri) end private def native_redirect_uri?(uri) self.class.native_redirect_uri.present? && uri.to_s == self.class.native_redirect_uri.to_s end def invalid_ssl_uri?(uri) forces_ssl = Doorkeeper.configuration.force_ssl_in_redirect_uri forces_ssl && uri.try(:scheme) != 'https' end end doorkeeper-2.2.1/app/controllers/0000755000076400007640000000000012544753400016041 5ustar pravipravidoorkeeper-2.2.1/app/controllers/doorkeeper/0000755000076400007640000000000012544753400020200 5ustar pravipravidoorkeeper-2.2.1/app/controllers/doorkeeper/authorized_applications_controller.rb0000644000076400007640000000074612544753400027723 0ustar pravipravimodule Doorkeeper class AuthorizedApplicationsController < Doorkeeper::ApplicationController before_filter :authenticate_resource_owner! def index @applications = Application.authorized_for(current_resource_owner) end def destroy AccessToken.revoke_all_for params[:id], current_resource_owner redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy]) end end end doorkeeper-2.2.1/app/controllers/doorkeeper/token_info_controller.rb0000644000076400007640000000063612544753400025130 0ustar pravipravimodule Doorkeeper class TokenInfoController < Doorkeeper::ApplicationMetalController def show if doorkeeper_token && doorkeeper_token.accessible? render json: doorkeeper_token, status: :ok else error = OAuth::ErrorResponse.new(name: :invalid_request) response.headers.merge!(error.headers) render json: error.body, status: error.status end end end end doorkeeper-2.2.1/app/controllers/doorkeeper/application_controller.rb0000644000076400007640000000041712544753400025275 0ustar pravipravimodule Doorkeeper class ApplicationController < ActionController::Base include Helpers::Controller if ::Rails.version.to_i < 4 protect_from_forgery else protect_from_forgery with: :exception end helper 'doorkeeper/dashboard' end end doorkeeper-2.2.1/app/controllers/doorkeeper/applications_controller.rb0000644000076400007640000000267412544753400025467 0ustar pravipravimodule Doorkeeper class ApplicationsController < Doorkeeper::ApplicationController layout 'doorkeeper/admin' before_filter :authenticate_admin! before_filter :set_application, only: [:show, :edit, :update, :destroy] def index @applications = Application.all end def new @application = Application.new end def create @application = Application.new(application_params) if @application.save flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) redirect_to oauth_application_url(@application) else render :new end end def update if @application.update_attributes(application_params) flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :update]) redirect_to oauth_application_url(@application) else render :edit end end def destroy flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :destroy]) if @application.destroy redirect_to oauth_applications_url end private def set_application @application = Application.find(params[:id]) end def application_params if params.respond_to?(:permit) params.require(:doorkeeper_application).permit(:name, :redirect_uri) else params[:doorkeeper_application].slice(:name, :redirect_uri) rescue nil end end end end doorkeeper-2.2.1/app/controllers/doorkeeper/authorizations_controller.rb0000644000076400007640000000257412544753400026063 0ustar pravipravimodule Doorkeeper class AuthorizationsController < Doorkeeper::ApplicationController before_filter :authenticate_resource_owner! def new if pre_auth.authorizable? if skip_authorization? || matching_token? auth = authorization.authorize redirect_to auth.redirect_uri else render :new end else render :error end end # TODO: Handle raise invalid authorization def create redirect_or_render authorization.authorize end def destroy redirect_or_render authorization.deny end private def matching_token? AccessToken.matching_token_for pre_auth.client, current_resource_owner.id, pre_auth.scopes end def redirect_or_render(auth) if auth.redirectable? redirect_to auth.redirect_uri else render json: auth.body, status: auth.status end end def pre_auth @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration, server.client_via_uid, params) end def authorization @authorization ||= strategy.request end def strategy @strategy ||= server.authorization_request pre_auth.response_type end end end doorkeeper-2.2.1/app/controllers/doorkeeper/application_metal_controller.rb0000644000076400007640000000057712544753400026466 0ustar pravipravimodule Doorkeeper class ApplicationMetalController < ActionController::Metal MODULES = [ ActionController::RackDelegation, ActionController::Instrumentation, AbstractController::Rendering, ActionController::Rendering, ActionController::Renderers::All, Helpers::Controller ] MODULES.each do |mod| include mod end end end doorkeeper-2.2.1/app/controllers/doorkeeper/tokens_controller.rb0000644000076400007640000000267612544753400024306 0ustar pravipravimodule Doorkeeper class TokensController < Doorkeeper::ApplicationMetalController def create response = authorize_response self.headers.merge! response.headers self.response_body = response.body.to_json self.status = response.status rescue Errors::DoorkeeperError => e handle_token_exception e end # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009 def revoke # The authorization server first validates the client credentials if doorkeeper_token && doorkeeper_token.accessible? # Doorkeeper does not use the token_type_hint logic described in the RFC 7009 # due to the refresh token implementation that is a field in the access token model. revoke_token(request.POST['token']) if request.POST['token'] end # The authorization server responds with HTTP status code 200 if the # token has been revoked successfully or if the client submitted an invalid token render json: {}, status: 200 end private def revoke_token(token) token = AccessToken.by_token(token) || AccessToken.by_refresh_token(token) if token && doorkeeper_token.same_credential?(token) token.revoke true else false end end def strategy @strategy ||= server.token_request params[:grant_type] end def authorize_response @authorize_response ||= strategy.authorize end end end doorkeeper-2.2.1/Gemfile0000644000076400007640000000014412544753400014205 0ustar pravipraviENV['rails'] ||= '4.2.0' source 'https://rubygems.org' gem 'rails', "~> #{ENV['rails']}" gemspec doorkeeper-2.2.1/metadata.yml0000644000076400007640000005142312544753400015223 0ustar pravipravi--- !ruby/object:Gem::Specification name: doorkeeper version: !ruby/object:Gem::Version version: 2.2.1 platform: ruby authors: - Felipe Elias Philipp - Tute Costa autorequire: bindir: bin cert_chain: [] date: 2015-05-05 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: railties requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3.2' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3.2' - !ruby/object:Gem::Dependency name: sqlite3 requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.3.5 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.3.5 - !ruby/object:Gem::Dependency name: rspec-rails requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 3.2.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 3.2.0 - !ruby/object:Gem::Dependency name: capybara requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 2.3.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 2.3.0 - !ruby/object:Gem::Dependency name: generator_spec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.9.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.9.0 - !ruby/object:Gem::Dependency name: factory_girl requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 4.5.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 4.5.0 - !ruby/object:Gem::Dependency name: timecop requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.7.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.7.0 - !ruby/object:Gem::Dependency name: database_cleaner requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.3.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.3.0 - !ruby/object:Gem::Dependency name: rspec-activemodel-mocks requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.0.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 1.0.0 - !ruby/object:Gem::Dependency name: bcrypt-ruby requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 3.0.1 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 3.0.1 - !ruby/object:Gem::Dependency name: pry requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.10.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.10.0 description: Doorkeeper is an OAuth 2 provider for Rails and Grape. email: - tutecosta@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".hound.yml" - ".rspec" - ".travis.yml" - CHANGELOG.md - CONTRIBUTING.md - Gemfile - MIT-LICENSE - NEWS.md - README.md - RELEASING.md - Rakefile - app/assets/stylesheets/doorkeeper/admin/application.css - app/assets/stylesheets/doorkeeper/application.css - app/controllers/doorkeeper/application_controller.rb - app/controllers/doorkeeper/application_metal_controller.rb - app/controllers/doorkeeper/applications_controller.rb - app/controllers/doorkeeper/authorizations_controller.rb - app/controllers/doorkeeper/authorized_applications_controller.rb - app/controllers/doorkeeper/token_info_controller.rb - app/controllers/doorkeeper/tokens_controller.rb - app/helpers/doorkeeper/dashboard_helper.rb - app/validators/redirect_uri_validator.rb - app/views/doorkeeper/applications/_delete_form.html.erb - app/views/doorkeeper/applications/_form.html.erb - app/views/doorkeeper/applications/edit.html.erb - app/views/doorkeeper/applications/index.html.erb - app/views/doorkeeper/applications/new.html.erb - app/views/doorkeeper/applications/show.html.erb - app/views/doorkeeper/authorizations/error.html.erb - app/views/doorkeeper/authorizations/new.html.erb - app/views/doorkeeper/authorizations/show.html.erb - app/views/doorkeeper/authorized_applications/_delete_form.html.erb - app/views/doorkeeper/authorized_applications/index.html.erb - app/views/layouts/doorkeeper/admin.html.erb - app/views/layouts/doorkeeper/application.html.erb - config/locales/en.yml - doorkeeper.gemspec - gemfiles/Gemfile.common.rb - gemfiles/Gemfile.mongo_mapper.rb - gemfiles/Gemfile.mongoid2.rb - gemfiles/Gemfile.mongoid3.rb - gemfiles/Gemfile.mongoid4.rb - lib/doorkeeper.rb - lib/doorkeeper/config.rb - lib/doorkeeper/engine.rb - lib/doorkeeper/errors.rb - lib/doorkeeper/generators/doorkeeper/mongo_mapper/indexes_generator.rb - lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/indexes.rb - lib/doorkeeper/grape/authorization_decorator.rb - lib/doorkeeper/grape/helpers.rb - lib/doorkeeper/helpers/controller.rb - lib/doorkeeper/models/access_grant_mixin.rb - lib/doorkeeper/models/access_token_mixin.rb - lib/doorkeeper/models/application_mixin.rb - lib/doorkeeper/models/concerns/accessible.rb - lib/doorkeeper/models/concerns/expirable.rb - lib/doorkeeper/models/concerns/ownership.rb - lib/doorkeeper/models/concerns/revocable.rb - lib/doorkeeper/models/concerns/scopes.rb - lib/doorkeeper/oauth/authorization/code.rb - lib/doorkeeper/oauth/authorization/token.rb - lib/doorkeeper/oauth/authorization/uri_builder.rb - lib/doorkeeper/oauth/authorization_code_request.rb - lib/doorkeeper/oauth/client.rb - lib/doorkeeper/oauth/client/credentials.rb - lib/doorkeeper/oauth/client/methods.rb - lib/doorkeeper/oauth/client_credentials/creator.rb - lib/doorkeeper/oauth/client_credentials/issuer.rb - lib/doorkeeper/oauth/client_credentials/validation.rb - lib/doorkeeper/oauth/client_credentials_request.rb - lib/doorkeeper/oauth/code_request.rb - lib/doorkeeper/oauth/code_response.rb - lib/doorkeeper/oauth/error.rb - lib/doorkeeper/oauth/error_response.rb - lib/doorkeeper/oauth/forbidden_token_response.rb - lib/doorkeeper/oauth/helpers/scope_checker.rb - lib/doorkeeper/oauth/helpers/unique_token.rb - lib/doorkeeper/oauth/helpers/uri_checker.rb - lib/doorkeeper/oauth/invalid_token_response.rb - lib/doorkeeper/oauth/password_access_token_request.rb - lib/doorkeeper/oauth/pre_authorization.rb - lib/doorkeeper/oauth/refresh_token_request.rb - lib/doorkeeper/oauth/request_concern.rb - lib/doorkeeper/oauth/scopes.rb - lib/doorkeeper/oauth/token.rb - lib/doorkeeper/oauth/token_request.rb - lib/doorkeeper/oauth/token_response.rb - lib/doorkeeper/orm/active_record.rb - lib/doorkeeper/orm/active_record/access_grant.rb - lib/doorkeeper/orm/active_record/access_token.rb - lib/doorkeeper/orm/active_record/application.rb - lib/doorkeeper/orm/mongo_mapper.rb - lib/doorkeeper/orm/mongo_mapper/access_grant.rb - lib/doorkeeper/orm/mongo_mapper/access_token.rb - lib/doorkeeper/orm/mongo_mapper/application.rb - lib/doorkeeper/orm/mongoid2.rb - lib/doorkeeper/orm/mongoid2/access_grant.rb - lib/doorkeeper/orm/mongoid2/access_token.rb - lib/doorkeeper/orm/mongoid2/application.rb - lib/doorkeeper/orm/mongoid2/concerns/scopes.rb - lib/doorkeeper/orm/mongoid3.rb - lib/doorkeeper/orm/mongoid3/access_grant.rb - lib/doorkeeper/orm/mongoid3/access_token.rb - lib/doorkeeper/orm/mongoid3/application.rb - lib/doorkeeper/orm/mongoid3/concerns/scopes.rb - lib/doorkeeper/orm/mongoid4.rb - lib/doorkeeper/orm/mongoid4/access_grant.rb - lib/doorkeeper/orm/mongoid4/access_token.rb - lib/doorkeeper/orm/mongoid4/application.rb - lib/doorkeeper/orm/mongoid4/concerns/scopes.rb - lib/doorkeeper/rails/helpers.rb - lib/doorkeeper/rails/routes.rb - lib/doorkeeper/rails/routes/mapper.rb - lib/doorkeeper/rails/routes/mapping.rb - lib/doorkeeper/request.rb - lib/doorkeeper/request/authorization_code.rb - lib/doorkeeper/request/client_credentials.rb - lib/doorkeeper/request/code.rb - lib/doorkeeper/request/password.rb - lib/doorkeeper/request/refresh_token.rb - lib/doorkeeper/request/token.rb - lib/doorkeeper/server.rb - lib/doorkeeper/validations.rb - lib/doorkeeper/version.rb - lib/generators/doorkeeper/application_owner_generator.rb - lib/generators/doorkeeper/application_scopes_generator.rb - lib/generators/doorkeeper/install_generator.rb - lib/generators/doorkeeper/migration_generator.rb - lib/generators/doorkeeper/templates/README - lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb - lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb - lib/generators/doorkeeper/templates/initializer.rb - lib/generators/doorkeeper/templates/migration.rb - lib/generators/doorkeeper/views_generator.rb - spec/controllers/applications_controller_spec.rb - spec/controllers/authorizations_controller_spec.rb - spec/controllers/protected_resources_controller_spec.rb - spec/controllers/token_info_controller_spec.rb - spec/controllers/tokens_controller_spec.rb - spec/dummy/Rakefile - spec/dummy/app/controllers/application_controller.rb - spec/dummy/app/controllers/custom_authorizations_controller.rb - spec/dummy/app/controllers/full_protected_resources_controller.rb - spec/dummy/app/controllers/home_controller.rb - spec/dummy/app/controllers/metal_controller.rb - spec/dummy/app/controllers/semi_protected_resources_controller.rb - spec/dummy/app/helpers/application_helper.rb - spec/dummy/app/models/user.rb - spec/dummy/app/views/home/index.html.erb - spec/dummy/app/views/layouts/application.html.erb - spec/dummy/config.ru - spec/dummy/config/application.rb - spec/dummy/config/boot.rb - spec/dummy/config/database.yml - spec/dummy/config/environment.rb - spec/dummy/config/environments/development.rb - spec/dummy/config/environments/production.rb - spec/dummy/config/environments/test.rb - spec/dummy/config/initializers/backtrace_silencers.rb - spec/dummy/config/initializers/doorkeeper.rb - spec/dummy/config/initializers/secret_token.rb - spec/dummy/config/initializers/session_store.rb - spec/dummy/config/initializers/wrap_parameters.rb - spec/dummy/config/locales/doorkeeper.en.yml - spec/dummy/config/mongo.yml - spec/dummy/config/mongoid2.yml - spec/dummy/config/mongoid3.yml - spec/dummy/config/mongoid4.yml - spec/dummy/config/routes.rb - spec/dummy/db/migrate/20111122132257_create_users.rb - spec/dummy/db/migrate/20120312140401_add_password_to_users.rb - spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb - spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb - spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb - spec/dummy/db/schema.rb - spec/dummy/public/404.html - spec/dummy/public/422.html - spec/dummy/public/500.html - spec/dummy/public/favicon.ico - spec/dummy/script/rails - spec/factories.rb - spec/generators/application_owner_generator_spec.rb - spec/generators/install_generator_spec.rb - spec/generators/migration_generator_spec.rb - spec/generators/templates/routes.rb - spec/generators/views_generator_spec.rb - spec/lib/config_spec.rb - spec/lib/doorkeeper_spec.rb - spec/lib/models/expirable_spec.rb - spec/lib/models/revocable_spec.rb - spec/lib/models/scopes_spec.rb - spec/lib/oauth/authorization/uri_builder_spec.rb - spec/lib/oauth/authorization_code_request_spec.rb - spec/lib/oauth/client/credentials_spec.rb - spec/lib/oauth/client/methods_spec.rb - spec/lib/oauth/client_credentials/creator_spec.rb - spec/lib/oauth/client_credentials/issuer_spec.rb - spec/lib/oauth/client_credentials/validation_spec.rb - spec/lib/oauth/client_credentials_integration_spec.rb - spec/lib/oauth/client_credentials_request_spec.rb - spec/lib/oauth/client_spec.rb - spec/lib/oauth/code_request_spec.rb - spec/lib/oauth/error_response_spec.rb - spec/lib/oauth/error_spec.rb - spec/lib/oauth/forbidden_token_response_spec.rb - spec/lib/oauth/helpers/scope_checker_spec.rb - spec/lib/oauth/helpers/unique_token_spec.rb - spec/lib/oauth/helpers/uri_checker_spec.rb - spec/lib/oauth/invalid_token_response_spec.rb - spec/lib/oauth/password_access_token_request_spec.rb - spec/lib/oauth/pre_authorization_spec.rb - spec/lib/oauth/refresh_token_request_spec.rb - spec/lib/oauth/scopes_spec.rb - spec/lib/oauth/token_request_spec.rb - spec/lib/oauth/token_response_spec.rb - spec/lib/oauth/token_spec.rb - spec/lib/server_spec.rb - spec/models/doorkeeper/access_grant_spec.rb - spec/models/doorkeeper/access_token_spec.rb - spec/models/doorkeeper/application_spec.rb - spec/requests/applications/applications_request_spec.rb - spec/requests/applications/authorized_applications_spec.rb - spec/requests/endpoints/authorization_spec.rb - spec/requests/endpoints/token_spec.rb - spec/requests/flows/authorization_code_errors_spec.rb - spec/requests/flows/authorization_code_spec.rb - spec/requests/flows/client_credentials_spec.rb - spec/requests/flows/implicit_grant_errors_spec.rb - spec/requests/flows/implicit_grant_spec.rb - spec/requests/flows/password_spec.rb - spec/requests/flows/refresh_token_spec.rb - spec/requests/flows/revoke_token_spec.rb - spec/requests/flows/skip_authorization_spec.rb - spec/requests/protected_resources/metal_spec.rb - spec/requests/protected_resources/private_api_spec.rb - spec/routing/custom_controller_routes_spec.rb - spec/routing/default_routes_spec.rb - spec/routing/scoped_routes_spec.rb - spec/spec_helper.rb - spec/spec_helper_integration.rb - spec/support/dependencies/factory_girl.rb - spec/support/helpers/access_token_request_helper.rb - spec/support/helpers/authorization_request_helper.rb - spec/support/helpers/config_helper.rb - spec/support/helpers/model_helper.rb - spec/support/helpers/request_spec_helper.rb - spec/support/helpers/url_helper.rb - spec/support/orm/active_record.rb - spec/support/orm/mongo_mapper.rb - spec/support/orm/mongoid.rb - spec/support/shared/controllers_shared_context.rb - spec/support/shared/models_shared_examples.rb - spec/validators/redirect_uri_validator_spec.rb - vendor/assets/stylesheets/doorkeeper/bootstrap.min.css homepage: https://github.com/doorkeeper-gem/doorkeeper licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.5 signing_key: specification_version: 4 summary: OAuth 2 provider for Rails and Grape test_files: - spec/controllers/applications_controller_spec.rb - spec/controllers/authorizations_controller_spec.rb - spec/controllers/protected_resources_controller_spec.rb - spec/controllers/token_info_controller_spec.rb - spec/controllers/tokens_controller_spec.rb - spec/dummy/Rakefile - spec/dummy/app/controllers/application_controller.rb - spec/dummy/app/controllers/custom_authorizations_controller.rb - spec/dummy/app/controllers/full_protected_resources_controller.rb - spec/dummy/app/controllers/home_controller.rb - spec/dummy/app/controllers/metal_controller.rb - spec/dummy/app/controllers/semi_protected_resources_controller.rb - spec/dummy/app/helpers/application_helper.rb - spec/dummy/app/models/user.rb - spec/dummy/app/views/home/index.html.erb - spec/dummy/app/views/layouts/application.html.erb - spec/dummy/config.ru - spec/dummy/config/application.rb - spec/dummy/config/boot.rb - spec/dummy/config/database.yml - spec/dummy/config/environment.rb - spec/dummy/config/environments/development.rb - spec/dummy/config/environments/production.rb - spec/dummy/config/environments/test.rb - spec/dummy/config/initializers/backtrace_silencers.rb - spec/dummy/config/initializers/doorkeeper.rb - spec/dummy/config/initializers/secret_token.rb - spec/dummy/config/initializers/session_store.rb - spec/dummy/config/initializers/wrap_parameters.rb - spec/dummy/config/locales/doorkeeper.en.yml - spec/dummy/config/mongo.yml - spec/dummy/config/mongoid2.yml - spec/dummy/config/mongoid3.yml - spec/dummy/config/mongoid4.yml - spec/dummy/config/routes.rb - spec/dummy/db/migrate/20111122132257_create_users.rb - spec/dummy/db/migrate/20120312140401_add_password_to_users.rb - spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb - spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb - spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb - spec/dummy/db/schema.rb - spec/dummy/public/404.html - spec/dummy/public/422.html - spec/dummy/public/500.html - spec/dummy/public/favicon.ico - spec/dummy/script/rails - spec/factories.rb - spec/generators/application_owner_generator_spec.rb - spec/generators/install_generator_spec.rb - spec/generators/migration_generator_spec.rb - spec/generators/templates/routes.rb - spec/generators/views_generator_spec.rb - spec/lib/config_spec.rb - spec/lib/doorkeeper_spec.rb - spec/lib/models/expirable_spec.rb - spec/lib/models/revocable_spec.rb - spec/lib/models/scopes_spec.rb - spec/lib/oauth/authorization/uri_builder_spec.rb - spec/lib/oauth/authorization_code_request_spec.rb - spec/lib/oauth/client/credentials_spec.rb - spec/lib/oauth/client/methods_spec.rb - spec/lib/oauth/client_credentials/creator_spec.rb - spec/lib/oauth/client_credentials/issuer_spec.rb - spec/lib/oauth/client_credentials/validation_spec.rb - spec/lib/oauth/client_credentials_integration_spec.rb - spec/lib/oauth/client_credentials_request_spec.rb - spec/lib/oauth/client_spec.rb - spec/lib/oauth/code_request_spec.rb - spec/lib/oauth/error_response_spec.rb - spec/lib/oauth/error_spec.rb - spec/lib/oauth/forbidden_token_response_spec.rb - spec/lib/oauth/helpers/scope_checker_spec.rb - spec/lib/oauth/helpers/unique_token_spec.rb - spec/lib/oauth/helpers/uri_checker_spec.rb - spec/lib/oauth/invalid_token_response_spec.rb - spec/lib/oauth/password_access_token_request_spec.rb - spec/lib/oauth/pre_authorization_spec.rb - spec/lib/oauth/refresh_token_request_spec.rb - spec/lib/oauth/scopes_spec.rb - spec/lib/oauth/token_request_spec.rb - spec/lib/oauth/token_response_spec.rb - spec/lib/oauth/token_spec.rb - spec/lib/server_spec.rb - spec/models/doorkeeper/access_grant_spec.rb - spec/models/doorkeeper/access_token_spec.rb - spec/models/doorkeeper/application_spec.rb - spec/requests/applications/applications_request_spec.rb - spec/requests/applications/authorized_applications_spec.rb - spec/requests/endpoints/authorization_spec.rb - spec/requests/endpoints/token_spec.rb - spec/requests/flows/authorization_code_errors_spec.rb - spec/requests/flows/authorization_code_spec.rb - spec/requests/flows/client_credentials_spec.rb - spec/requests/flows/implicit_grant_errors_spec.rb - spec/requests/flows/implicit_grant_spec.rb - spec/requests/flows/password_spec.rb - spec/requests/flows/refresh_token_spec.rb - spec/requests/flows/revoke_token_spec.rb - spec/requests/flows/skip_authorization_spec.rb - spec/requests/protected_resources/metal_spec.rb - spec/requests/protected_resources/private_api_spec.rb - spec/routing/custom_controller_routes_spec.rb - spec/routing/default_routes_spec.rb - spec/routing/scoped_routes_spec.rb - spec/spec_helper.rb - spec/spec_helper_integration.rb - spec/support/dependencies/factory_girl.rb - spec/support/helpers/access_token_request_helper.rb - spec/support/helpers/authorization_request_helper.rb - spec/support/helpers/config_helper.rb - spec/support/helpers/model_helper.rb - spec/support/helpers/request_spec_helper.rb - spec/support/helpers/url_helper.rb - spec/support/orm/active_record.rb - spec/support/orm/mongo_mapper.rb - spec/support/orm/mongoid.rb - spec/support/shared/controllers_shared_context.rb - spec/support/shared/models_shared_examples.rb - spec/validators/redirect_uri_validator_spec.rb doorkeeper-2.2.1/lib/0000755000076400007640000000000012544753400013461 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper.rb0000644000076400007640000000433112544753400016146 0ustar pravipravirequire 'doorkeeper/version' require 'doorkeeper/engine' require 'doorkeeper/config' require 'doorkeeper/errors' require 'doorkeeper/server' require 'doorkeeper/request' require 'doorkeeper/validations' require 'doorkeeper/oauth/authorization/code' require 'doorkeeper/oauth/authorization/token' require 'doorkeeper/oauth/authorization/uri_builder' require 'doorkeeper/oauth/helpers/scope_checker' require 'doorkeeper/oauth/helpers/uri_checker' require 'doorkeeper/oauth/helpers/unique_token' require 'doorkeeper/oauth/scopes' require 'doorkeeper/oauth/error' require 'doorkeeper/oauth/code_response' require 'doorkeeper/oauth/token_response' require 'doorkeeper/oauth/error_response' require 'doorkeeper/oauth/pre_authorization' require 'doorkeeper/oauth/request_concern' require 'doorkeeper/oauth/authorization_code_request' require 'doorkeeper/oauth/refresh_token_request' require 'doorkeeper/oauth/password_access_token_request' require 'doorkeeper/oauth/client_credentials_request' require 'doorkeeper/oauth/code_request' require 'doorkeeper/oauth/token_request' require 'doorkeeper/oauth/client' require 'doorkeeper/oauth/token' require 'doorkeeper/oauth/invalid_token_response' require 'doorkeeper/oauth/forbidden_token_response' require 'doorkeeper/models/concerns/scopes' require 'doorkeeper/models/concerns/expirable' require 'doorkeeper/models/concerns/revocable' require 'doorkeeper/models/concerns/accessible' require 'doorkeeper/models/access_grant_mixin' require 'doorkeeper/models/access_token_mixin' require 'doorkeeper/models/application_mixin' require 'doorkeeper/helpers/controller' require 'doorkeeper/rails/routes' require 'doorkeeper/rails/helpers' require 'doorkeeper/orm/active_record' require 'doorkeeper/orm/mongo_mapper' require 'doorkeeper/orm/mongoid2' require 'doorkeeper/orm/mongoid3' require 'doorkeeper/orm/mongoid4' module Doorkeeper def self.configured? @config.present? end def self.database_installed? [AccessToken, AccessGrant, Application].all? { |model| model.table_exists? } end def self.installed? configured? && database_installed? end def self.authenticate(request, methods = Doorkeeper.configuration.access_token_methods) OAuth::Token.authenticate(request, *methods) end end doorkeeper-2.2.1/lib/generators/0000755000076400007640000000000012544753400015632 5ustar pravipravidoorkeeper-2.2.1/lib/generators/doorkeeper/0000755000076400007640000000000012544753400017771 5ustar pravipravidoorkeeper-2.2.1/lib/generators/doorkeeper/install_generator.rb0000644000076400007640000000067212544753400024037 0ustar pravipraviclass Doorkeeper::InstallGenerator < ::Rails::Generators::Base include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) desc 'Installs Doorkeeper.' def install template 'initializer.rb', 'config/initializers/doorkeeper.rb' copy_file File.expand_path('../../../../config/locales/en.yml', __FILE__), 'config/locales/doorkeeper.en.yml' route 'use_doorkeeper' readme 'README' end end doorkeeper-2.2.1/lib/generators/doorkeeper/migration_generator.rb0000644000076400007640000000072412544753400024360 0ustar pravipravirequire 'rails/generators/active_record' class Doorkeeper::MigrationGenerator < ::Rails::Generators::Base include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) desc 'Installs Doorkeeper migration file.' def install migration_template 'migration.rb', 'db/migrate/create_doorkeeper_tables.rb' end def self.next_migration_number(dirname) ActiveRecord::Generators::Base.next_migration_number(dirname) end end doorkeeper-2.2.1/lib/generators/doorkeeper/application_scopes_generator.rb0000644000076400007640000000163612544753400026251 0ustar pravipravirequire 'rails/generators/active_record' class Doorkeeper::ApplicationScopesGenerator < Rails::Generators::Base include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) desc 'Copies ActiveRecord migrations to handle upgrade to doorkeeper 2' def self.next_migration_number(path) ActiveRecord::Generators::Base.next_migration_number(path) end def application_scopes if oauth_applications_exists? && !scopes_column_exists? migration_template( 'add_scopes_to_oauth_applications.rb', 'db/migrate/add_scopes_to_oauth_applications.rb' ) end end private def scopes_column_exists? ActiveRecord::Base.connection.column_exists?( :oauth_applications, :scopes ) end # Might be running this before install def oauth_applications_exists? ActiveRecord::Base.connection.table_exists? :oauth_applications end end doorkeeper-2.2.1/lib/generators/doorkeeper/application_owner_generator.rb0000644000076400007640000000103512544753400026100 0ustar pravipravirequire 'rails/generators/active_record' class Doorkeeper::ApplicationOwnerGenerator < Rails::Generators::Base include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) desc 'Provide support for client application ownership.' def application_owner migration_template( 'add_owner_to_application_migration.rb', 'db/migrate/add_owner_to_application.rb' ) end def self.next_migration_number(dirname) ActiveRecord::Generators::Base.next_migration_number(dirname) end end doorkeeper-2.2.1/lib/generators/doorkeeper/templates/0000755000076400007640000000000012544753400021767 5ustar pravipravidoorkeeper-2.2.1/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb0000644000076400007640000000024312544753400031067 0ustar pravipraviclass AddScopesToOauthApplications < ActiveRecord::Migration def change add_column :oauth_applications, :scopes, :string, null: false, default: '' end end doorkeeper-2.2.1/lib/generators/doorkeeper/templates/migration.rb0000644000076400007640000000257612544753400024317 0ustar pravipraviclass CreateDoorkeeperTables < ActiveRecord::Migration def change create_table :oauth_applications do |t| t.string :name, null: false t.string :uid, null: false t.string :secret, null: false t.text :redirect_uri, null: false t.string :scopes, null: false, default: '' t.timestamps end add_index :oauth_applications, :uid, unique: true create_table :oauth_access_grants do |t| t.integer :resource_owner_id, null: false t.integer :application_id, null: false t.string :token, null: false t.integer :expires_in, null: false t.text :redirect_uri, null: false t.datetime :created_at, null: false t.datetime :revoked_at t.string :scopes end add_index :oauth_access_grants, :token, unique: true create_table :oauth_access_tokens do |t| t.integer :resource_owner_id t.integer :application_id t.string :token, null: false t.string :refresh_token t.integer :expires_in t.datetime :revoked_at t.datetime :created_at, null: false t.string :scopes end add_index :oauth_access_tokens, :token, unique: true add_index :oauth_access_tokens, :resource_owner_id add_index :oauth_access_tokens, :refresh_token, unique: true end end doorkeeper-2.2.1/lib/generators/doorkeeper/templates/README0000644000076400007640000000152312544753400022650 0ustar pravipravi=============================================================================== There is a setup that you need to do before you can use doorkeeper. Step 1. Go to config/initializers/doorkeeper.rb and configure resource_owner_authenticator block. Step 2. Choose the ORM: If you want to use ActiveRecord run: rails generate doorkeeper:migration And run rake db:migrate If you want to use Mongoid, configure the orm in initializers/doorkeeper.rb: # Mongoid Doorkeeper.configure do orm :mongoid end If you want to use MongoMapper, configure the orm in initializers/doorkeeper.rb: # MongoMapper Doorkeeper.configure do orm :mongo_mapper end And run rails generate doorkeeper:mongo_mapper:indexes rake db:index Step 3. That's it, that's all. Enjoy! =============================================================================== doorkeeper-2.2.1/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb0000644000076400007640000000042112544753400031411 0ustar pravipraviclass AddOwnerToApplication < ActiveRecord::Migration def change add_column :oauth_applications, :owner_id, :integer, null: true add_column :oauth_applications, :owner_type, :string, null: true add_index :oauth_applications, [:owner_id, :owner_type] end enddoorkeeper-2.2.1/lib/generators/doorkeeper/templates/initializer.rb0000644000076400007640000001170612544753400024644 0ustar pravipraviDoorkeeper.configure do # Change the ORM that doorkeeper will use. # Currently supported options are :active_record, :mongoid2, :mongoid3, # :mongoid4, :mongo_mapper orm :active_record # This block will be called to check whether the resource owner is authenticated or not. resource_owner_authenticator do fail "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}" # Put your resource owner authentication logic here. # Example implementation: # User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url) end # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. # admin_authenticator do # # Put your admin authentication logic here. # # Example implementation: # Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url) # end # Authorization Code expiration time (default 10 minutes). # authorization_code_expires_in 10.minutes # Access token expiration time (default 2 hours). # If you want to disable expiration, set this to nil. # access_token_expires_in 2.hours # Assign a custom TTL for implicit grants. # custom_access_token_expires_in do |oauth_client| # oauth_client.application.additional_settings.implicit_oauth_expiration # end # Use a custom class for generating the access token. # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator # access_token_generator "::Doorkeeper::JWT" # Reuse access token for the same resource owner within an application (disabled by default) # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383 # reuse_access_token # Issue access tokens with refresh token (disabled by default) # use_refresh_token # Provide support for an owner to be assigned to each registered application (disabled by default) # Optional parameter :confirmation => true (default false) if you want to enforce ownership of # a registered application # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support # enable_application_owner :confirmation => false # Define access token scopes for your provider # For more information go to # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes # default_scopes :public # optional_scopes :write, :update # Change the way client credentials are retrieved from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:client_id` and `:client_secret` params from the `params` object. # Check out the wiki for more information on customization # client_credentials :from_basic, :from_params # Change the way access token is authenticated from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:access_token` or `:bearer_token` params from the `params` object. # Check out the wiki for more information on customization # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param # Change the native redirect uri for client apps # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi) # # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob' # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled # by default in non-development environments). OAuth2 delegates security in # communication to the HTTPS protocol so it is wise to keep this enabled. # # force_ssl_in_redirect_uri !Rails.env.development? # Specify what grant flows are enabled in array of Strings. The valid # strings and the flows they enable are: # # "authorization_code" => Authorization Code Grant Flow # "implicit" => Implicit Grant Flow # "password" => Resource Owner Password Credentials Grant Flow # "client_credentials" => Client Credentials Grant Flow # # If not specified, Doorkeeper enables authorization_code and # client_credentials. # # implicit and password grant flows have risks that you should understand # before enabling: # http://tools.ietf.org/html/rfc6819#section-4.4.2 # http://tools.ietf.org/html/rfc6819#section-4.4.3 # # grant_flows %w(authorization_code client_credentials) # Under some circumstances you might want to have applications auto-approved, # so that the user skips the authorization step. # For example if dealing with a trusted application. # skip_authorization do |resource_owner, client| # client.superapp? or resource_owner.admin? # end # WWW-Authenticate Realm (default "Doorkeeper"). # realm "Doorkeeper" end doorkeeper-2.2.1/lib/generators/doorkeeper/views_generator.rb0000644000076400007640000000063612544753400023526 0ustar pravipravimodule Doorkeeper module Generators class ViewsGenerator < ::Rails::Generators::Base source_root File.expand_path('../../../../app/views', __FILE__) desc 'Copies default Doorkeeper views and layouts to your application.' def manifest directory 'doorkeeper', 'app/views/doorkeeper' directory 'layouts/doorkeeper', 'app/views/layouts/doorkeeper' end end end end doorkeeper-2.2.1/lib/doorkeeper/0000755000076400007640000000000012544753400015620 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/errors.rb0000644000076400007640000000061512544753400017463 0ustar pravipravimodule Doorkeeper module Errors class DoorkeeperError < StandardError end class InvalidAuthorizationStrategy < DoorkeeperError end class InvalidTokenStrategy < DoorkeeperError end class MissingRequestStrategy < DoorkeeperError end class UnableToGenerateToken < DoorkeeperError end class TokenGeneratorNotFound < DoorkeeperError end end end doorkeeper-2.2.1/lib/doorkeeper/validations.rb0000644000076400007640000000107412544753400020464 0ustar pravipravimodule Doorkeeper module Validations extend ActiveSupport::Concern attr_accessor :error def validate @error = nil self.class.validations.each do |validation| break if @error @error = validation.last unless send("validate_#{validation.first}") end end def valid? validate @error.nil? end module ClassMethods def validate(attribute, options = {}) validations << [attribute, options[:error]] end def validations @validations ||= [] end end end end doorkeeper-2.2.1/lib/doorkeeper/request.rb0000644000076400007640000000165212544753400017641 0ustar pravipravirequire 'doorkeeper/request/authorization_code' require 'doorkeeper/request/client_credentials' require 'doorkeeper/request/code' require 'doorkeeper/request/password' require 'doorkeeper/request/refresh_token' require 'doorkeeper/request/token' module Doorkeeper module Request module_function def authorization_strategy(strategy) get_strategy strategy, Doorkeeper.configuration.authorization_response_types rescue NameError raise Errors::InvalidAuthorizationStrategy end def token_strategy(strategy) get_strategy strategy, Doorkeeper.configuration.token_grant_types rescue NameError raise Errors::InvalidTokenStrategy end def get_strategy(strategy, available) fail Errors::MissingRequestStrategy unless strategy.present? fail NameError unless available.include?(strategy.to_s) "Doorkeeper::Request::#{strategy.to_s.camelize}".constantize end end end doorkeeper-2.2.1/lib/doorkeeper/request/0000755000076400007640000000000012544753400017310 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/request/password.rb0000644000076400007640000000113712544753400021501 0ustar pravipravimodule Doorkeeper module Request class Password def self.build(server) new(server.credentials, server.resource_owner, server) end attr_accessor :credentials, :resource_owner, :server def initialize(credentials, resource_owner, server) @credentials, @resource_owner, @server = credentials, resource_owner, server end def request @request ||= OAuth::PasswordAccessTokenRequest.new(Doorkeeper.configuration, credentials, resource_owner, server.parameters) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/request/token.rb0000644000076400007640000000072412544753400020760 0ustar pravipravimodule Doorkeeper module Request class Token def self.build(server) new(server.context.send(:pre_auth), server) end attr_accessor :pre_auth, :server def initialize(pre_auth, server) @pre_auth, @server = pre_auth, server end def request @request ||= OAuth::TokenRequest.new(pre_auth, server.current_resource_owner) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/request/refresh_token.rb0000644000076400007640000000113612544753400022474 0ustar pravipravimodule Doorkeeper module Request class RefreshToken def self.build(server) new(server.current_refresh_token, server.credentials, server) end attr_accessor :refresh_token, :credentials, :server def initialize(refresh_token, credentials, server) @refresh_token, @credentials, @server = refresh_token, credentials, server end def request @request ||= OAuth::RefreshTokenRequest.new(Doorkeeper.configuration, refresh_token, credentials, server.parameters) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/request/code.rb0000644000076400007640000000072212544753400020550 0ustar pravipravimodule Doorkeeper module Request class Code def self.build(server) new(server.context.send(:pre_auth), server) end attr_accessor :pre_auth, :server def initialize(pre_auth, server) @pre_auth, @server = pre_auth, server end def request @request ||= OAuth::CodeRequest.new(pre_auth, server.current_resource_owner) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/request/client_credentials.rb0000644000076400007640000000073712544753400023477 0ustar pravipravimodule Doorkeeper module Request class ClientCredentials def self.build(server) new(server.client, server) end attr_accessor :client, :server def initialize(client, server) @client, @server = client, server end def request @request ||= OAuth::ClientCredentialsRequest.new(Doorkeeper.configuration, client, server.parameters) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/request/authorization_code.rb0000644000076400007640000000102212544753400023522 0ustar pravipravimodule Doorkeeper module Request class AuthorizationCode def self.build(server) new(server.grant, server.client, server) end attr_accessor :grant, :client, :server def initialize(grant, client, server) @grant, @client, @server = grant, client, server end def request @request ||= OAuth::AuthorizationCodeRequest.new(Doorkeeper.configuration, grant, client, server.parameters) end def authorize request.authorize end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/0000755000076400007640000000000012544753400016415 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/0000755000076400007640000000000012544753400020135 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/access_grant.rb0000644000076400007640000000106712544753400023122 0ustar pravipravirequire 'doorkeeper/orm/mongoid4/concerns/scopes' module Doorkeeper class AccessGrant include Mongoid::Document include Mongoid::Timestamps include AccessGrantMixin include Models::Mongoid4::Scopes self.store_in collection: :oauth_access_grants field :resource_owner_id, type: BSON::ObjectId field :application_id, type: BSON::ObjectId field :token, type: String field :expires_in, type: Integer field :redirect_uri, type: String field :revoked_at, type: DateTime index({ token: 1 }, { unique: true }) end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/access_token.rb0000644000076400007640000000170312544753400023124 0ustar pravipravirequire 'doorkeeper/orm/mongoid4/concerns/scopes' module Doorkeeper class AccessToken include Mongoid::Document include Mongoid::Timestamps include AccessTokenMixin include Models::Mongoid4::Scopes self.store_in collection: :oauth_access_tokens field :resource_owner_id, type: BSON::ObjectId field :application_id, type: BSON::ObjectId field :token, type: String field :refresh_token, type: String field :expires_in, type: Integer field :revoked_at, type: DateTime index({ token: 1 }, { unique: true }) index({ refresh_token: 1 }, { unique: true, sparse: true }) def self.delete_all_for(application_id, resource_owner) where(application_id: application_id, resource_owner_id: resource_owner.id).delete_all end private_class_method :delete_all_for def self.order_method :order_by end def self.created_at_desc [:created_at, :desc] end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/application.rb0000644000076400007640000000120712544753400022765 0ustar pravipravimodule Doorkeeper class Application include Mongoid::Document include Mongoid::Timestamps include Models::Mongoid4::Scopes include ApplicationMixin self.store_in collection: :oauth_applications field :name, type: String field :uid, type: String field :secret, type: String field :redirect_uri, type: String index({ uid: 1 }, { unique: true }) has_many :authorized_tokens, class_name: 'Doorkeeper::AccessToken' def self.authorized_for(resource_owner) ids = AccessToken.where(resource_owner_id: resource_owner.id, revoked_at: nil).map(&:application_id) find(ids) end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/concerns/0000755000076400007640000000000012544753400021747 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4/concerns/scopes.rb0000644000076400007640000000046612544753400023576 0ustar pravipravimodule Doorkeeper module Models module Mongoid4 module Scopes extend ActiveSupport::Concern included do field :scopes, type: String end def scopes=(value) write_attribute :scopes, value if value.present? end end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongo_mapper/0000755000076400007640000000000012544753400021100 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongo_mapper/access_grant.rb0000644000076400007640000000100312544753400024053 0ustar pravipravimodule Doorkeeper class AccessGrant include MongoMapper::Document include AccessGrantMixin safe timestamps! set_collection_name 'oauth_access_grants' key :resource_owner_id, ObjectId key :application_id, ObjectId key :token, String key :scopes, String key :expires_in, Integer key :redirect_uri, String key :revoked_at, DateTime def self.create_indexes ensure_index :token, unique: true end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongo_mapper/access_token.rb0000644000076400007640000000170712544753400024073 0ustar pravipravimodule Doorkeeper class AccessToken include MongoMapper::Document include AccessTokenMixin safe timestamps! set_collection_name 'oauth_access_tokens' key :resource_owner_id, ObjectId key :application_id, ObjectId key :token, String key :refresh_token, String key :expires_in, Integer key :revoked_at, DateTime key :scopes, String def self.last self.sort(:created_at).last end def self.delete_all_for(application_id, resource_owner) delete_all(application_id: application_id, resource_owner_id: resource_owner.id) end private_class_method :delete_all_for def self.create_indexes ensure_index :token, unique: true ensure_index [[:refresh_token, 1]], unique: true, sparse: true end def self.order_method :sort end def self.created_at_desc :created_at.desc end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongo_mapper/application.rb0000644000076400007640000000125412544753400023732 0ustar pravipravimodule Doorkeeper class Application include MongoMapper::Document include ApplicationMixin safe timestamps! set_collection_name 'oauth_applications' many :authorized_tokens, class_name: 'Doorkeeper::AccessToken' key :name, String key :uid, String key :secret, String key :redirect_uri, String key :scopes, String def self.authorized_for(resource_owner) ids = AccessToken.where( resource_owner_id: resource_owner.id, revoked_at: nil ).map(&:application_id) find(ids) end def self.create_indexes ensure_index :uid, unique: true end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid4.rb0000644000076400007640000000100412544753400020455 0ustar pravipravimodule Doorkeeper module Orm module Mongoid4 def self.initialize_models! require 'doorkeeper/orm/mongoid4/access_grant' require 'doorkeeper/orm/mongoid4/access_token' require 'doorkeeper/orm/mongoid4/application' end def self.initialize_application_owner! require 'doorkeeper/models/concerns/ownership' Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership end def self.check_requirements!(_config); end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/0000755000076400007640000000000012544753400020134 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/access_grant.rb0000644000076400007640000000110512544753400023112 0ustar pravipravirequire 'doorkeeper/orm/mongoid3/concerns/scopes' module Doorkeeper class AccessGrant include Mongoid::Document include Mongoid::Timestamps include AccessGrantMixin include Models::Mongoid3::Scopes self.store_in collection: :oauth_access_grants field :resource_owner_id, type: Moped::BSON::ObjectId field :application_id, type: Moped::BSON::ObjectId field :token, type: String field :expires_in, type: Integer field :redirect_uri, type: String field :revoked_at, type: DateTime index({ token: 1 }, { unique: true }) end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/access_token.rb0000644000076400007640000000172112544753400023123 0ustar pravipravirequire 'doorkeeper/orm/mongoid3/concerns/scopes' module Doorkeeper class AccessToken include Mongoid::Document include Mongoid::Timestamps include AccessTokenMixin include Models::Mongoid3::Scopes self.store_in collection: :oauth_access_tokens field :resource_owner_id, type: Moped::BSON::ObjectId field :application_id, type: Moped::BSON::ObjectId field :token, type: String field :refresh_token, type: String field :expires_in, type: Integer field :revoked_at, type: DateTime index({ token: 1 }, { unique: true }) index({ refresh_token: 1 }, { unique: true, sparse: true }) def self.delete_all_for(application_id, resource_owner) where(application_id: application_id, resource_owner_id: resource_owner.id).delete_all end private_class_method :delete_all_for def self.order_method :order_by end def self.created_at_desc [:created_at, :desc] end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/application.rb0000644000076400007640000000120712544753400022764 0ustar pravipravimodule Doorkeeper class Application include Mongoid::Document include Mongoid::Timestamps include Models::Mongoid3::Scopes include ApplicationMixin self.store_in collection: :oauth_applications field :name, type: String field :uid, type: String field :secret, type: String field :redirect_uri, type: String index({ uid: 1 }, { unique: true }) has_many :authorized_tokens, class_name: 'Doorkeeper::AccessToken' def self.authorized_for(resource_owner) ids = AccessToken.where(resource_owner_id: resource_owner.id, revoked_at: nil).map(&:application_id) find(ids) end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/concerns/0000755000076400007640000000000012544753400021746 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3/concerns/scopes.rb0000644000076400007640000000142012544753400023564 0ustar pravipravimodule Doorkeeper module Models module Mongoid3 module Scopes extend ActiveSupport::Concern # It's strange that if not define these after included will raise error # in Mongoid 2 and 3, but 4 works well see: # https://travis-ci.org/jasl/doorkeeper/builds/31586902 included do def scopes OAuth::Scopes.from_string(self[:scopes]) end def scopes_string self[:scopes] end def includes_scope?(*required_scopes) required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) } end def scopes=(value) write_attribute :scopes, value if value.present? end end end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid3.rb0000644000076400007640000000100412544753400020454 0ustar pravipravimodule Doorkeeper module Orm module Mongoid3 def self.initialize_models! require 'doorkeeper/orm/mongoid3/access_grant' require 'doorkeeper/orm/mongoid3/access_token' require 'doorkeeper/orm/mongoid3/application' end def self.initialize_application_owner! require 'doorkeeper/models/concerns/ownership' Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership end def self.check_requirements!(_config); end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2.rb0000644000076400007640000000100412544753400020453 0ustar pravipravimodule Doorkeeper module Orm module Mongoid2 def self.initialize_models! require 'doorkeeper/orm/mongoid2/access_grant' require 'doorkeeper/orm/mongoid2/access_token' require 'doorkeeper/orm/mongoid2/application' end def self.initialize_application_owner! require 'doorkeeper/models/concerns/ownership' Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership end def self.check_requirements!(_config); end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/0000755000076400007640000000000012544753400020133 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/access_grant.rb0000644000076400007640000000103112544753400023107 0ustar pravipravirequire 'doorkeeper/orm/mongoid2/concerns/scopes' module Doorkeeper class AccessGrant include Mongoid::Document include Mongoid::Timestamps include AccessGrantMixin include Models::Mongoid2::Scopes self.store_in :oauth_access_grants field :resource_owner_id, type: Integer field :application_id, type: BSON::ObjectId field :token, type: String field :expires_in, type: Integer field :redirect_uri, type: String field :revoked_at, type: DateTime index :token, unique: true end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/access_token.rb0000644000076400007640000000163212544753400023123 0ustar pravipravirequire 'doorkeeper/orm/mongoid2/concerns/scopes' module Doorkeeper class AccessToken include Mongoid::Document include Mongoid::Timestamps include AccessTokenMixin include Models::Mongoid2::Scopes self.store_in :oauth_access_tokens field :resource_owner_id, type: Integer field :application_id, type: BSON::ObjectId field :token, type: String field :refresh_token, type: String field :expires_in, type: Integer field :revoked_at, type: DateTime index :token, unique: true index :refresh_token, unique: true, sparse: true def self.delete_all_for(application_id, resource_owner) where(application_id: application_id, resource_owner_id: resource_owner.id).delete_all end private_class_method :delete_all_for def self.order_method :order_by end def self.created_at_desc [:created_at, :desc] end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/application.rb0000644000076400007640000000116012544753400022761 0ustar pravipravimodule Doorkeeper class Application include Mongoid::Document include Mongoid::Timestamps include Models::Mongoid2::Scopes include ApplicationMixin self.store_in :oauth_applications field :name, type: String field :uid, type: String field :secret, type: String field :redirect_uri, type: String index :uid, unique: true has_many :authorized_tokens, class_name: 'Doorkeeper::AccessToken' def self.authorized_for(resource_owner) ids = AccessToken.where(resource_owner_id: resource_owner.id, revoked_at: nil).map(&:application_id) find(ids) end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/concerns/0000755000076400007640000000000012544753400021745 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/mongoid2/concerns/scopes.rb0000644000076400007640000000142012544753400023563 0ustar pravipravimodule Doorkeeper module Models module Mongoid2 module Scopes extend ActiveSupport::Concern # It's strange that if not define these after included will raise error # in Mongoid 2 and 3, but 4 works well see: # https://travis-ci.org/jasl/doorkeeper/builds/31586902 included do def scopes OAuth::Scopes.from_string(self[:scopes]) end def scopes_string self[:scopes] end def includes_scope?(*required_scopes) required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) } end def scopes=(value) write_attribute :scopes, value if value.present? end end end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/active_record/0000755000076400007640000000000012544753400021226 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/orm/active_record/access_grant.rb0000644000076400007640000000027612544753400024214 0ustar pravipravimodule Doorkeeper class AccessGrant < ActiveRecord::Base include AccessGrantMixin self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}".to_sym end end doorkeeper-2.2.1/lib/doorkeeper/orm/active_record/access_token.rb0000644000076400007640000000100312544753400024206 0ustar pravipravimodule Doorkeeper class AccessToken < ActiveRecord::Base include AccessTokenMixin self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym def self.delete_all_for(application_id, resource_owner) where(application_id: application_id, resource_owner_id: resource_owner.id).delete_all end private_class_method :delete_all_for def self.order_method :order end def self.created_at_desc 'created_at desc' end end end doorkeeper-2.2.1/lib/doorkeeper/orm/active_record/application.rb0000644000076400007640000000154312544753400024061 0ustar pravipravimodule Doorkeeper class Application < ActiveRecord::Base include ApplicationMixin self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym if ActiveRecord::VERSION::MAJOR >= 4 has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: 'AccessToken' else has_many :authorized_tokens, class_name: 'AccessToken', conditions: { revoked_at: nil } end has_many :authorized_applications, through: :authorized_tokens, source: :application def self.column_names_with_table self.column_names.map { |c| "#{table_name}.#{c}" } end def self.authorized_for(resource_owner) joins(:authorized_applications). where(AccessToken.table_name => { resource_owner_id: resource_owner.id, revoked_at: nil }). group(column_names_with_table.join(',')) end end end doorkeeper-2.2.1/lib/doorkeeper/orm/mongo_mapper.rb0000644000076400007640000000102312544753400021421 0ustar pravipravimodule Doorkeeper module Orm module MongoMapper def self.initialize_models! require 'doorkeeper/orm/mongo_mapper/access_grant' require 'doorkeeper/orm/mongo_mapper/access_token' require 'doorkeeper/orm/mongo_mapper/application' end def self.initialize_application_owner! require 'doorkeeper/models/concerns/ownership' Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership end def self.check_requirements!(_config); end end end end doorkeeper-2.2.1/lib/doorkeeper/orm/active_record.rb0000644000076400007640000000243612544753400021560 0ustar pravipravimodule Doorkeeper module Orm module ActiveRecord def self.initialize_models! require 'doorkeeper/orm/active_record/access_grant' require 'doorkeeper/orm/active_record/access_token' require 'doorkeeper/orm/active_record/application' if Doorkeeper.configuration.active_record_options[:establish_connection] [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application].each do |c| c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection] end end end def self.initialize_application_owner! require 'doorkeeper/models/concerns/ownership' Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership end def self.check_requirements!(_config) if ::ActiveRecord::Base.connected? && ::ActiveRecord::Base.connection.table_exists?( Doorkeeper::Application.table_name ) unless Doorkeeper::Application.new.attributes.include?("scopes") fail <<-MSG.squish [doorkeeper] Missing column: `oauth_applications.scopes`. Run `rails generate doorkeeper:application_scopes && rake db:migrate` to add it. MSG end end end end end end doorkeeper-2.2.1/lib/doorkeeper/version.rb0000644000076400007640000000005212544753400017627 0ustar pravipravimodule Doorkeeper VERSION = '2.2.1' end doorkeeper-2.2.1/lib/doorkeeper/oauth/0000755000076400007640000000000012544753400016740 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/oauth/code_request.rb0000644000076400007640000000141712544753400021752 0ustar pravipravimodule Doorkeeper module OAuth class CodeRequest attr_accessor :pre_auth, :resource_owner, :client def initialize(pre_auth, resource_owner) @pre_auth = pre_auth @client = pre_auth.client @resource_owner = resource_owner end def authorize if pre_auth.authorizable? auth = Authorization::Code.new(pre_auth, resource_owner) auth.issue_token @response = CodeResponse.new pre_auth, auth else @response = ErrorResponse.from_request pre_auth end end def deny pre_auth.error = :access_denied ErrorResponse.from_request pre_auth, redirect_uri: pre_auth.redirect_uri end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/error_response.rb0000644000076400007640000000317212544753400022337 0ustar pravipravimodule Doorkeeper module OAuth class ErrorResponse include OAuth::Authorization::URIBuilder include OAuth::Helpers def self.from_request(request, attributes = {}) state = request.state if request.respond_to?(:state) new(attributes.merge(name: request.error, state: state)) end delegate :name, :description, :state, to: :@error def initialize(attributes = {}) @error = OAuth::Error.new(*attributes.values_at(:name, :state)) @redirect_uri = attributes[:redirect_uri] @response_on_fragment = attributes[:response_on_fragment] end def body { error: name, error_description: description, state: state }.reject { |_, v| v.blank? } end def status :unauthorized end def redirectable? name != :invalid_redirect_uri && name != :invalid_client && !URIChecker.native_uri?(@redirect_uri) end def redirect_uri if @response_on_fragment uri_with_fragment @redirect_uri, body else uri_with_query @redirect_uri, body end end def authenticate_info %(Bearer realm="#{realm}", error="#{name}", error_description="#{description}") end def headers { 'Cache-Control' => 'no-store', 'Pragma' => 'no-cache', 'Content-Type' => 'application/json; charset=utf-8', 'WWW-Authenticate' => authenticate_info } end protected delegate :realm, to: :configuration def configuration Doorkeeper.configuration end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/token.rb0000644000076400007640000000325312544753400020410 0ustar pravipravimodule Doorkeeper module OAuth class Token module Methods def from_access_token_param(request) request.parameters[:access_token] end def from_bearer_param(request) request.parameters[:bearer_token] end def from_bearer_authorization(request) pattern = /^Bearer /i header = request.authorization token_from_header(header, pattern) if match?(header, pattern) end def from_basic_authorization(request) pattern = /^Basic /i header = request.authorization token_from_basic_header(header, pattern) if match?(header, pattern) end private def token_from_basic_header(header, pattern) encoded_header = token_from_header(header, pattern) token, _ = decode_basic_credentials(encoded_header) token end def decode_basic_credentials(encoded_header) Base64.decode64(encoded_header).split(/:/, 2) end def token_from_header(header, pattern) header.gsub pattern, '' end def match?(header, pattern) header && header.match(pattern) end end extend Methods def self.from_request(request, *methods) methods.inject(nil) do |credentials, method| method = self.method(method) if method.is_a?(Symbol) credentials = method.call(request) break credentials unless credentials.blank? end end def self.authenticate(request, *methods) if token = from_request(request, *methods) AccessToken.by_token(token) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/authorization/0000755000076400007640000000000012544753400021640 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/oauth/authorization/uri_builder.rb0000644000076400007640000000130712544753400024473 0ustar pravipravimodule Doorkeeper module OAuth module Authorization module URIBuilder include Rack::Utils extend self def uri_with_query(url, parameters = {}) uri = URI.parse(url) original_query = parse_query(uri.query) uri.query = build_query(original_query.merge(parameters)) uri.to_s end def uri_with_fragment(url, parameters = {}) uri = URI.parse(url) uri.fragment = build_query(parameters) uri.to_s end def build_query(parameters = {}) parameters = parameters.reject { |k, v| v.blank? } super parameters end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/authorization/token.rb0000644000076400007640000000274612544753400023316 0ustar pravipravimodule Doorkeeper module OAuth module Authorization class Token attr_accessor :pre_auth, :resource_owner, :token def initialize(pre_auth, resource_owner) @pre_auth = pre_auth @resource_owner = resource_owner end def self.access_token_expires_in(server, pre_auth_or_oauth_client) if expiration = custom_expiration(server, pre_auth_or_oauth_client) expiration else server.access_token_expires_in end end def issue_token @token ||= AccessToken.find_or_create_for( pre_auth.client, resource_owner.id, pre_auth.scopes, self.class.access_token_expires_in(configuration, pre_auth), false ) end def native_redirect { controller: 'doorkeeper/token_info', action: :show, access_token: token.token } end private def self.custom_expiration(server, pre_auth_or_oauth_client) oauth_client = if pre_auth_or_oauth_client.respond_to?(:client) pre_auth_or_oauth_client.client else pre_auth_or_oauth_client end server.custom_access_token_expires_in.call(oauth_client) end def configuration Doorkeeper.configuration end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/authorization/code.rb0000644000076400007640000000145412544753400023103 0ustar pravipravimodule Doorkeeper module OAuth module Authorization class Code attr_accessor :pre_auth, :resource_owner, :token def initialize(pre_auth, resource_owner) @pre_auth = pre_auth @resource_owner = resource_owner end def issue_token @token ||= AccessGrant.create!( application_id: pre_auth.client.id, resource_owner_id: resource_owner.id, expires_in: configuration.authorization_code_expires_in, redirect_uri: pre_auth.redirect_uri, scopes: pre_auth.scopes.to_s ) end def native_redirect { action: :show, code: token.token } end def configuration Doorkeeper.configuration end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client_credentials/0000755000076400007640000000000012544753400022573 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/oauth/client_credentials/issuer.rb0000644000076400007640000000167112544753400024437 0ustar pravipravirequire 'doorkeeper/oauth/client_credentials/validation' module Doorkeeper module OAuth class ClientCredentialsRequest class Issuer attr_accessor :token, :validation, :error def initialize(server, validation) @server, @validation = server, validation end def create(client, scopes, creator = Creator.new) if validation.valid? @token = create_token(client, scopes, creator) @error = :server_error unless @token else @token = false @error = validation.error end @token end private def create_token(client, scopes, creator) ttl = Authorization::Token.access_token_expires_in(@server, client) creator.call( client, scopes, use_refresh_token: false, expires_in: ttl ) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client_credentials/creator.rb0000644000076400007640000000046512544753400024564 0ustar pravipravimodule Doorkeeper module OAuth class ClientCredentialsRequest class Creator def call(client, scopes, attributes = {}) AccessToken.create(attributes.merge( application_id: client.id, scopes: scopes.to_s )) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client_credentials/validation.rb0000644000076400007640000000206112544753400025251 0ustar pravipravirequire 'doorkeeper/validations' require 'doorkeeper/oauth/scopes' require 'doorkeeper/oauth/helpers/scope_checker' module Doorkeeper module OAuth class ClientCredentialsRequest class Validation include Validations include OAuth::Helpers validate :client, error: :invalid_client validate :scopes, error: :invalid_scope def initialize(server, request) @server, @request, @client = server, request, request.client validate end private def validate_client @client.present? end def validate_scopes return true unless @request.scopes.present? application_scopes = if @client.present? @client.application.scopes else '' end ScopeChecker.valid?( @request.scopes.to_s, @server.scopes, application_scopes ) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/password_access_token_request.rb0000644000076400007640000000244612544753400025426 0ustar pravipravimodule Doorkeeper module OAuth class PasswordAccessTokenRequest include Validations include OAuth::RequestConcern include OAuth::Helpers validate :client, error: :invalid_client validate :resource_owner, error: :invalid_grant validate :scopes, error: :invalid_scope attr_accessor :server, :resource_owner, :credentials, :access_token attr_accessor :client def initialize(server, credentials, resource_owner, parameters = {}) @server = server @resource_owner = resource_owner @credentials = credentials @original_scopes = parameters[:scope] if credentials @client = Application.by_uid_and_secret credentials.uid, credentials.secret end end private def before_successful_response find_or_create_access_token(client, resource_owner.id, scopes, server) end def validate_scopes return true unless @original_scopes.present? ScopeChecker.valid? @original_scopes, server.scopes, client.try(:scopes) end def validate_resource_owner !!resource_owner end def validate_client !credentials || !!client end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client_credentials_request.rb0000644000076400007640000000160112544753400024666 0ustar pravipravirequire 'doorkeeper/oauth/client_credentials/creator' require 'doorkeeper/oauth/client_credentials/issuer' require 'doorkeeper/oauth/client_credentials/validation' module Doorkeeper module OAuth class ClientCredentialsRequest include Validations include OAuth::RequestConcern attr_accessor :issuer, :server, :client, :original_scopes attr_reader :response alias :error_response :response delegate :error, to: :issuer def issuer @issuer ||= Issuer.new(server, Validation.new(server, self)) end def initialize(server, client, parameters = {}) @client, @server = client, server @response = nil @original_scopes = parameters[:scope] end def access_token issuer.token end private def valid? issuer.create(client, scopes) end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/token_request.rb0000644000076400007640000000175712544753400022167 0ustar pravipravimodule Doorkeeper module OAuth class TokenRequest attr_accessor :pre_auth, :resource_owner, :client def initialize(pre_auth, resource_owner) @pre_auth = pre_auth @client = pre_auth.client @resource_owner = resource_owner end def authorize if pre_auth.authorizable? auth = Authorization::Token.new(pre_auth, resource_owner) auth.issue_token @response = CodeResponse.new pre_auth, auth, response_on_fragment: true else @response = error_response end end def deny pre_auth.error = :access_denied error_response end private def error_response ErrorResponse.from_request pre_auth, redirect_uri: pre_auth.redirect_uri, response_on_fragment: true end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/helpers/0000755000076400007640000000000012544753400020402 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/oauth/helpers/scope_checker.rb0000644000076400007640000000242612544753400023530 0ustar pravipravimodule Doorkeeper module OAuth module Helpers module ScopeChecker class Validator attr_reader :parsed_scopes, :scope_str def initialize(scope_str, server_scopes, application_scopes) @parsed_scopes = OAuth::Scopes.from_string(scope_str) @scope_str = scope_str @valid_scopes = valid_scopes(server_scopes, application_scopes) end def valid? scope_str.present? && scope_str !~ /[\n|\r|\t]/ && @valid_scopes.has_scopes?(parsed_scopes) end def match? valid? && parsed_scopes.has_scopes?(@valid_scopes) end private def valid_scopes(server_scopes, application_scopes) if application_scopes.present? server_scopes & application_scopes else server_scopes end end end def self.valid?(scope_str, server_scopes, application_scopes = nil) Validator.new(scope_str, server_scopes, application_scopes).valid? end def self.match?(scope_str, server_scopes, application_scopes = nil) Validator.new(scope_str, server_scopes, application_scopes).match? end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/helpers/uri_checker.rb0000644000076400007640000000143512544753400023215 0ustar pravipravimodule Doorkeeper module OAuth module Helpers module URIChecker def self.valid?(url) uri = as_uri(url) uri.fragment.nil? && !uri.host.nil? && !uri.scheme.nil? rescue URI::InvalidURIError false end def self.matches?(url, client_url) url, client_url = as_uri(url), as_uri(client_url) url.query = nil url == client_url end def self.valid_for_authorization?(url, client_url) valid?(url) && client_url.split.any? { |other_url| matches?(url, other_url) } end def self.as_uri(url) URI.parse(url) end def self.native_uri?(url) url == Doorkeeper.configuration.native_redirect_uri end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/helpers/unique_token.rb0000644000076400007640000000053412544753400023437 0ustar pravipravimodule Doorkeeper module OAuth module Helpers module UniqueToken def self.generate(options = {}) generator_method = options.delete(:generator) || SecureRandom.method(:hex) token_size = options.delete(:size) || 32 generator_method.call(token_size) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/refresh_token_request.rb0000644000076400007640000000431412544753400023675 0ustar pravipravimodule Doorkeeper module OAuth class RefreshTokenRequest include Validations include OAuth::RequestConcern include OAuth::Helpers validate :token_presence, error: :invalid_request validate :token, error: :invalid_grant validate :client, error: :invalid_client validate :client_match, error: :invalid_grant validate :scope, error: :invalid_scope attr_accessor :access_token, :client, :credentials, :refresh_token, :server def initialize(server, refresh_token, credentials, parameters = {}) @server = server @refresh_token = refresh_token @credentials = credentials @original_scopes = parameters[:scope] || parameters[:scopes] @refresh_token_parameter = parameters[:refresh_token] if credentials @client = Application.by_uid_and_secret credentials.uid, credentials.secret end end private attr_reader :refresh_token_parameter def before_successful_response refresh_token.revoke create_access_token end def default_scopes refresh_token.scopes end def create_access_token expires_in = Authorization::Token.access_token_expires_in( server, client ) @access_token = AccessToken.create!( application_id: refresh_token.application_id, resource_owner_id: refresh_token.resource_owner_id, scopes: scopes.to_s, expires_in: expires_in, use_refresh_token: true) end def validate_token_presence refresh_token.present? || refresh_token_parameter.present? end def validate_token refresh_token.present? && !refresh_token.revoked? end def validate_client !credentials || !!client end def validate_client_match !client || refresh_token.application_id == client.id end def validate_scope if @original_scopes.present? ScopeChecker.valid?(@original_scopes, refresh_token.scopes) else true end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/token_response.rb0000644000076400007640000000135512544753400022327 0ustar pravipravimodule Doorkeeper module OAuth class TokenResponse attr_accessor :token def initialize(token) @token = token end def body { 'access_token' => token.token, 'token_type' => token.token_type, 'expires_in' => token.expires_in_seconds, 'refresh_token' => token.refresh_token, 'scope' => token.scopes_string, 'created_at' => token.created_at.to_i, }.reject { |_, value| value.blank? } end def status :ok end def headers { 'Cache-Control' => 'no-store', 'Pragma' => 'no-cache', 'Content-Type' => 'application/json; charset=utf-8' } end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/request_concern.rb0000644000076400007640000000215412544753400022466 0ustar pravipravimodule Doorkeeper module OAuth module RequestConcern def authorize validate if valid? before_successful_response @response = TokenResponse.new(access_token) after_successful_response @response else @response = ErrorResponse.from_request(self) end end def scopes @scopes ||= if @original_scopes.present? OAuth::Scopes.from_string(@original_scopes) else default_scopes end end def default_scopes server.default_scopes end def valid? error.nil? end def find_or_create_access_token(client, resource_owner_id, scopes, server) @access_token = AccessToken.find_or_create_for( client, resource_owner_id, scopes, Authorization::Token.access_token_expires_in(server, client), server.refresh_token_enabled?) end def before_successful_response end def after_successful_response end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/scopes.rb0000644000076400007640000000225412544753400020564 0ustar pravipravimodule Doorkeeper module OAuth class Scopes include Enumerable include Comparable def self.from_string(string) string ||= '' new.tap do |scope| scope.add(*string.split) end end def self.from_array(array) new.tap do |scope| scope.add(*array) end end delegate :each, :empty?, to: :@scopes def initialize @scopes = [] end def exists?(scope) @scopes.include? scope.to_s end def add(*scopes) @scopes.push(*scopes.map(&:to_s)) @scopes.uniq! end def all @scopes end def to_s @scopes.join(' ') end def has_scopes?(scopes) scopes.all? { |s| exists?(s) } end def +(other) if other.is_a? Scopes self.class.from_array(self.all + other.all) else super(other) end end def <=>(other) self.map(&:to_s).sort <=> other.map(&:to_s).sort end def &(other) other_array = other.present? ? other.all : [] self.class.from_array(all & other_array) end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/error.rb0000644000076400007640000000030512544753400020414 0ustar pravipravimodule Doorkeeper module OAuth class Error < Struct.new(:name, :state) def description I18n.translate name, scope: [:doorkeeper, :errors, :messages] end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/code_response.rb0000644000076400007640000000203412544753400022114 0ustar pravipravimodule Doorkeeper module OAuth class CodeResponse include OAuth::Authorization::URIBuilder include OAuth::Helpers attr_accessor :pre_auth, :auth, :response_on_fragment def initialize(pre_auth, auth, options = {}) @pre_auth, @auth = pre_auth, auth @response_on_fragment = options[:response_on_fragment] end def redirectable? true end def redirect_uri if URIChecker.native_uri? pre_auth.redirect_uri auth.native_redirect else if response_on_fragment uri_with_fragment( pre_auth.redirect_uri, access_token: auth.token.token, token_type: auth.token.token_type, expires_in: auth.token.expires_in, state: pre_auth.state ) else uri_with_query pre_auth.redirect_uri, code: auth.token.token, state: pre_auth.state end end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/invalid_token_response.rb0000644000076400007640000000145012544753400024031 0ustar pravipravimodule Doorkeeper module OAuth class InvalidTokenResponse < ErrorResponse def self.from_access_token(access_token, attributes = {}) reason = case when access_token.try(:revoked?) :revoked when access_token.try(:expired?) :expired else :unknown end new(attributes.merge(reason: reason)) end def initialize(attributes = {}) super(attributes.merge(name: :invalid_token, state: :unauthorized)) @reason = attributes[:reason] || :unknown end def description scope = { scope: [:doorkeeper, :errors, :messages, :invalid_token] } @description ||= I18n.translate @reason, scope end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client/0000755000076400007640000000000012544753400020216 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/oauth/client/methods.rb0000644000076400007640000000066312544753400022213 0ustar pravipravimodule Doorkeeper module OAuth class Client module Methods def from_params(request) request.parameters.values_at(:client_id, :client_secret) end def from_basic(request) authorization = request.authorization if authorization.present? && authorization =~ /^Basic (.*)/m Base64.decode64($1).split(/:/, 2) end end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client/credentials.rb0000644000076400007640000000106312544753400023040 0ustar pravipravimodule Doorkeeper module OAuth class Client class Credentials < Struct.new(:uid, :secret) extend Methods def self.from_request(request, *credentials_methods) credentials_methods.inject(nil) do |credentials, method| method = self.method(method) if method.is_a?(Symbol) credentials = Credentials.new *method.call(request) break credentials unless credentials.blank? end end def blank? uid.blank? || secret.blank? end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/forbidden_token_response.rb0000644000076400007640000000126112544753400024337 0ustar pravipravimodule Doorkeeper module OAuth class ForbiddenTokenResponse < ErrorResponse def self.from_scopes(scopes, attributes = {}) new(attributes.merge(scopes: scopes)) end def initialize(attributes = {}) super(attributes.merge(name: :invalid_scope, state: :forbidden)) @scopes = attributes[:scopes] end def status :forbidden end def headers headers = super headers.delete 'WWW-Authenticate' headers end def description scope = { scope: [:doorkeeper, :scopes] } @description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n') end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/client.rb0000644000076400007640000000136712544753400020552 0ustar pravipravirequire 'doorkeeper/oauth/client/methods' require 'doorkeeper/oauth/client/credentials' module Doorkeeper module OAuth class Client attr_accessor :application delegate :id, :name, :uid, :redirect_uri, :scopes, to: :@application def initialize(application) @application = application end def self.find(uid, method = Application.method(:by_uid)) if application = method.call(uid) new(application) end end def self.authenticate(credentials, method = Application.method(:by_uid_and_secret)) return false if credentials.blank? if application = method.call(credentials.uid, credentials.secret) new(application) end end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/pre_authorization.rb0000644000076400007640000000323712544753400023040 0ustar pravipravimodule Doorkeeper module OAuth class PreAuthorization include Validations validate :response_type, error: :unsupported_response_type validate :client, error: :invalid_client validate :scopes, error: :invalid_scope validate :redirect_uri, error: :invalid_redirect_uri attr_accessor :server, :client, :response_type, :redirect_uri, :state attr_writer :scope def initialize(server, client, attrs = {}) @server = server @client = client @response_type = attrs[:response_type] @redirect_uri = attrs[:redirect_uri] @scope = attrs[:scope] @state = attrs[:state] end def authorizable? valid? end def scopes Scopes.from_string scope end def scope @scope.presence || server.default_scopes.to_s end def error_response OAuth::ErrorResponse.from_request(self) end private def validate_response_type server.authorization_response_types.include? response_type end def validate_client client.present? end def validate_scopes return true unless scope.present? Helpers::ScopeChecker.valid?( scope, server.scopes, client.application.scopes ) end # TODO: test uri should be matched against the client's one def validate_redirect_uri return false unless redirect_uri.present? Helpers::URIChecker.native_uri?(redirect_uri) || Helpers::URIChecker.valid_for_authorization?(redirect_uri, client.redirect_uri) end end end end doorkeeper-2.2.1/lib/doorkeeper/oauth/authorization_code_request.rb0000644000076400007640000000236612544753400024736 0ustar pravipravimodule Doorkeeper module OAuth class AuthorizationCodeRequest include Validations include OAuth::RequestConcern validate :attributes, error: :invalid_request validate :client, error: :invalid_client validate :grant, error: :invalid_grant validate :redirect_uri, error: :invalid_grant attr_accessor :server, :grant, :client, :redirect_uri, :access_token def initialize(server, grant, client, parameters = {}) @server = server @client = client @grant = grant @redirect_uri = parameters[:redirect_uri] end private def before_successful_response grant.revoke find_or_create_access_token(grant.application, grant.resource_owner_id, grant.scopes, server) end def validate_attributes redirect_uri.present? end def validate_client !!client end def validate_grant return false unless grant && grant.application_id == client.id grant.accessible? end def validate_redirect_uri grant.redirect_uri == redirect_uri end end end end doorkeeper-2.2.1/lib/doorkeeper/helpers/0000755000076400007640000000000012544753400017262 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/helpers/controller.rb0000644000076400007640000000335212544753400021775 0ustar pravipravimodule Doorkeeper module Helpers module Controller extend ActiveSupport::Concern private def authenticate_resource_owner! current_resource_owner end def current_resource_owner instance_eval(&Doorkeeper.configuration.authenticate_resource_owner) end def resource_owner_from_credentials instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials) end def authenticate_admin! instance_eval(&Doorkeeper.configuration.authenticate_admin) end def server @server ||= Server.new(self) end def doorkeeper_token @token ||= OAuth::Token.authenticate request, *config_methods end def config_methods @methods ||= Doorkeeper.configuration.access_token_methods end def get_error_response_from_exception(exception) error_name = case exception when Errors::InvalidTokenStrategy :unsupported_grant_type when Errors::InvalidAuthorizationStrategy :unsupported_response_type when Errors::MissingRequestStrategy :invalid_request end OAuth::ErrorResponse.new name: error_name, state: params[:state] end def handle_token_exception(exception) error = get_error_response_from_exception exception self.headers.merge! error.headers self.response_body = error.body.to_json self.status = error.status end def skip_authorization? !!instance_exec([@server.current_resource_owner, @pre_auth.client], &Doorkeeper.configuration.skip_authorization) end end end end doorkeeper-2.2.1/lib/doorkeeper/config.rb0000644000076400007640000001741412544753400017421 0ustar pravipravimodule Doorkeeper class MissingConfiguration < StandardError def initialize super('Configuration for doorkeeper missing. Do you have doorkeeper initializer?') end end def self.configure(&block) @config = Config::Builder.new(&block).build setup_orm_adapter setup_orm_models setup_application_owner if @config.enable_application_owner? check_requirements end def self.configuration @config || (fail MissingConfiguration.new) end def self.check_requirements @orm_adapter.check_requirements!(configuration) end def self.setup_orm_adapter @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize rescue NameError => e fail e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.squish [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error trying to load it. You probably need to add the related gem for this adapter to work with doorkeeper. ERROR_MSG end def self.setup_orm_models @orm_adapter.initialize_models! end def self.setup_application_owner @orm_adapter.initialize_application_owner! end class Config class Builder def initialize(&block) @config = Config.new instance_eval(&block) end def build @config end def enable_application_owner(opts = {}) @config.instance_variable_set('@enable_application_owner', true) confirm_application_owner if opts[:confirmation].present? && opts[:confirmation] end def confirm_application_owner @config.instance_variable_set('@confirm_application_owner', true) end def default_scopes(*scopes) @config.instance_variable_set('@default_scopes', OAuth::Scopes.from_array(scopes)) end def optional_scopes(*scopes) @config.instance_variable_set('@optional_scopes', OAuth::Scopes.from_array(scopes)) end def client_credentials(*methods) @config.instance_variable_set('@client_credentials', methods) end def access_token_methods(*methods) @config.instance_variable_set('@access_token_methods', methods) end def use_refresh_token @config.instance_variable_set('@refresh_token_enabled', true) end def realm(realm) @config.instance_variable_set('@realm', realm) end def reuse_access_token @config.instance_variable_set("@reuse_access_token", true) end def force_ssl_in_redirect_uri(boolean) @config.instance_variable_set("@force_ssl_in_redirect_uri", boolean) end def access_token_generator(access_token_generator) @config.instance_variable_set( '@access_token_generator', access_token_generator ) end end module Option # Defines configuration option # # When you call option, it defines two methods. One method will take place # in the +Config+ class and the other method will take place in the # +Builder+ class. # # The +name+ parameter will set both builder method and config attribute. # If the +:as+ option is defined, the builder method will be the specified # option while the config attribute will be the +name+ parameter. # # If you want to introduce another level of config DSL you can # define +builder_class+ parameter. # Builder should take a block as the initializer parameter and respond to function +build+ # that returns the value of the config attribute. # # ==== Options # # * [:+as+] Set the builder method that goes inside +configure+ block # * [+:default+] The default value in case no option was set # # ==== Examples # # option :name # option :name, as: :set_name # option :name, default: 'My Name' # option :scopes builder_class: ScopesBuilder # def option(name, options = {}) attribute = options[:as] || name attribute_builder = options[:builder_class] Builder.instance_eval do define_method name do |*args, &block| # TODO: is builder_class option being used? value = unless attribute_builder block ? block : args.first else attribute_builder.new(&block).build end @config.instance_variable_set(:"@#{attribute}", value) end end define_method attribute do |*args| if instance_variable_defined?(:"@#{attribute}") instance_variable_get(:"@#{attribute}") else options[:default] end end public attribute end def extended(base) base.send(:private, :option) end end extend Option option :resource_owner_authenticator, as: :authenticate_resource_owner, default: (lambda do |_routes| logger.warn(I18n.translate('doorkeeper.errors.messages.resource_owner_authenticator_not_configured')) nil end) option :admin_authenticator, as: :authenticate_admin, default: ->(_routes) {} option :resource_owner_from_credentials, default: (lambda do |_routes| warn(I18n.translate('doorkeeper.errors.messages.credential_flow_not_configured')) nil end) option :skip_authorization, default: ->(_routes) {} option :access_token_expires_in, default: 7200 option :custom_access_token_expires_in, default: lambda { |_app| nil } option :authorization_code_expires_in, default: 600 option :orm, default: :active_record option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob' option :active_record_options, default: {} option :realm, default: 'Doorkeeper' option :force_ssl_in_redirect_uri, default: !Rails.env.development? option :grant_flows, default: %w(authorization_code client_credentials) option :access_token_generator, default: "Doorkeeper::OAuth::Helpers::UniqueToken" attr_reader :reuse_access_token def refresh_token_enabled? !!@refresh_token_enabled end def enable_application_owner? !!@enable_application_owner end def confirm_application_owner? !!@confirm_application_owner end def default_scopes @default_scopes ||= OAuth::Scopes.new end def optional_scopes @optional_scopes ||= OAuth::Scopes.new end def scopes @scopes ||= default_scopes + optional_scopes end def client_credentials_methods @client_credentials ||= [:from_basic, :from_params] end def access_token_methods @access_token_methods ||= [:from_bearer_authorization, :from_access_token_param, :from_bearer_param] end def realm @realm ||= 'Doorkeeper' end def authorization_response_types @authorization_response_types ||= calculate_authorization_response_types end def token_grant_types @token_grant_types ||= calculate_token_grant_types end private # Determines what values are acceptable for 'response_type' param in # authorization request endpoint, and return them as an array of strings. # def calculate_authorization_response_types types = [] types << 'code' if grant_flows.include? 'authorization_code' types << 'token' if grant_flows.include? 'implicit' types end # Determines what values are acceptable for 'grant_type' param token # request endpoint, and return them in array. # def calculate_token_grant_types types = grant_flows - ['implicit'] types << 'refresh_token' if refresh_token_enabled? types end end end doorkeeper-2.2.1/lib/doorkeeper/engine.rb0000644000076400007640000000101612544753400017410 0ustar pravipravimodule Doorkeeper class Engine < Rails::Engine initializer "doorkeeper.params.filter" do |app| app.config.filter_parameters += [:client_secret, :code, :token] end initializer "doorkeeper.locales" do |app| app.config.i18n.fallbacks = [:en] end initializer "doorkeeper.routes" do Doorkeeper::Rails::Routes.install! end initializer "doorkeeper.helpers" do ActiveSupport.on_load(:action_controller) do include Doorkeeper::Rails::Helpers end end end end doorkeeper-2.2.1/lib/doorkeeper/models/0000755000076400007640000000000012544753400017103 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/models/access_token_mixin.rb0000644000076400007640000001061512544753400023300 0ustar pravipravimodule Doorkeeper module AccessTokenMixin extend ActiveSupport::Concern include OAuth::Helpers include Models::Expirable include Models::Revocable include Models::Accessible include Models::Scopes included do belongs_to :application, class_name: 'Doorkeeper::Application', inverse_of: :access_tokens validates :token, presence: true, uniqueness: true validates :refresh_token, uniqueness: true, if: :use_refresh_token? attr_writer :use_refresh_token if ::Rails.version.to_i < 4 || defined?(::ProtectedAttributes) attr_accessible :application_id, :resource_owner_id, :expires_in, :scopes, :use_refresh_token end before_validation :generate_token, on: :create before_validation :generate_refresh_token, on: :create, if: :use_refresh_token? end module ClassMethods def by_token(token) where(token: token.to_s).limit(1).to_a.first end def by_refresh_token(refresh_token) where(refresh_token: refresh_token.to_s).first end def revoke_all_for(application_id, resource_owner) where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil). map(&:revoke) end def matching_token_for(application, resource_owner_or_id, scopes) resource_owner_id = if resource_owner_or_id.respond_to?(:to_key) resource_owner_or_id.id else resource_owner_or_id end token = last_authorized_token_for(application.try(:id), resource_owner_id) if token && scopes_match?(token.scopes, scopes, application.try(:scopes)) token end end def scopes_match?(token_scopes, param_scopes, app_scopes) (!token_scopes.present? && !param_scopes.present?) || Doorkeeper::OAuth::Helpers::ScopeChecker.match?( token_scopes.to_s, param_scopes, app_scopes ) end def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token) if Doorkeeper.configuration.reuse_access_token access_token = matching_token_for(application, resource_owner_id, scopes) if access_token && !access_token.expired? return access_token end end create!( application_id: application.try(:id), resource_owner_id: resource_owner_id, scopes: scopes.to_s, expires_in: expires_in, use_refresh_token: use_refresh_token ) end def last_authorized_token_for(application_id, resource_owner_id) where(application_id: application_id, resource_owner_id: resource_owner_id, revoked_at: nil). send(order_method, created_at_desc). limit(1). to_a. first end end def token_type 'bearer' end def use_refresh_token? !!@use_refresh_token end def as_json(_options = {}) { resource_owner_id: resource_owner_id, scopes: scopes, expires_in_seconds: expires_in_seconds, application: { uid: application.try(:uid) }, created_at: created_at.to_i, } end # It indicates whether the tokens have the same credential def same_credential?(access_token) application_id == access_token.application_id && resource_owner_id == access_token.resource_owner_id end def acceptable?(scopes) accessible? && includes_scope?(*scopes) end private def generate_refresh_token write_attribute :refresh_token, UniqueToken.generate end def generate_token generator = Doorkeeper.configuration.access_token_generator.constantize self.token = generator.generate(resource_owner_id: resource_owner_id, scopes: scopes, application: application, expires_in: expires_in) rescue NoMethodError raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`." rescue NameError raise Errors::TokenGeneratorNotFound, "#{generator} not found" end end end doorkeeper-2.2.1/lib/doorkeeper/models/access_grant_mixin.rb0000644000076400007640000000165412544753400023276 0ustar pravipravimodule Doorkeeper module AccessGrantMixin extend ActiveSupport::Concern include OAuth::Helpers include Models::Expirable include Models::Revocable include Models::Accessible include Models::Scopes included do belongs_to :application, class_name: 'Doorkeeper::Application', inverse_of: :access_grants if ::Rails.version.to_i < 4 || defined?(::ProtectedAttributes) attr_accessible :resource_owner_id, :application_id, :expires_in, :redirect_uri, :scopes end validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true validates :token, uniqueness: true before_validation :generate_token, on: :create end module ClassMethods def by_token(token) where(token: token.to_s).limit(1).to_a.first end end private def generate_token self.token = UniqueToken.generate end end end doorkeeper-2.2.1/lib/doorkeeper/models/application_mixin.rb0000644000076400007640000000302412544753400023136 0ustar pravipravimodule Doorkeeper module ApplicationMixin extend ActiveSupport::Concern include OAuth::Helpers include Models::Scopes included do has_many :access_grants, dependent: :destroy, class_name: 'Doorkeeper::AccessGrant' has_many :access_tokens, dependent: :destroy, class_name: 'Doorkeeper::AccessToken' validates :name, :secret, :uid, presence: true validates :uid, uniqueness: true validates :redirect_uri, redirect_uri: true before_validation :generate_uid, :generate_secret, on: :create if ::Rails.version.to_i < 4 || defined?(::ProtectedAttributes) attr_accessible :name, :redirect_uri end end module ClassMethods def by_uid_and_secret(uid, secret) where(uid: uid.to_s, secret: secret.to_s).limit(1).to_a.first end def by_uid(uid) where(uid: uid.to_s).limit(1).to_a.first end end alias_method :original_scopes, :scopes def scopes if has_scopes? original_scopes else fail NameError, "Missing column: `applications.scopes`.", <<-MSG.squish If you are using ActiveRecord run `rails generate doorkeeper:application_scopes && rake db:migrate` to add it. MSG end end private def has_scopes? Doorkeeper.configuration.orm != :active_record || Application.new.attributes.include?("scopes") end def generate_uid self.uid ||= UniqueToken.generate end def generate_secret self.secret ||= UniqueToken.generate end end end doorkeeper-2.2.1/lib/doorkeeper/models/concerns/0000755000076400007640000000000012544753400020715 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/models/concerns/expirable.rb0000644000076400007640000000072312544753400023217 0ustar pravipravimodule Doorkeeper module Models module Expirable def expired? expires_in && Time.now > expired_time end def expires_in_seconds return nil if expires_in.nil? expires = (created_at + expires_in.seconds) - Time.now expires_sec = expires.seconds.round(0) expires_sec > 0 ? expires_sec : 0 end private def expired_time created_at + expires_in.seconds end end end end doorkeeper-2.2.1/lib/doorkeeper/models/concerns/revocable.rb0000644000076400007640000000037112544753400023205 0ustar pravipravimodule Doorkeeper module Models module Revocable def revoke(clock = DateTime) update_attribute :revoked_at, clock.now end def revoked? !!(revoked_at && revoked_at <= DateTime.now) end end end end doorkeeper-2.2.1/lib/doorkeeper/models/concerns/ownership.rb0000644000076400007640000000052712544753400023264 0ustar pravipravimodule Doorkeeper module Models module Ownership extend ActiveSupport::Concern included do belongs_to :owner, polymorphic: true validates :owner, presence: true, if: :validate_owner? end def validate_owner? Doorkeeper.configuration.confirm_application_owner? end end end end doorkeeper-2.2.1/lib/doorkeeper/models/concerns/accessible.rb0000644000076400007640000000021112544753400023331 0ustar pravipravimodule Doorkeeper module Models module Accessible def accessible? !expired? && !revoked? end end end end doorkeeper-2.2.1/lib/doorkeeper/models/concerns/scopes.rb0000644000076400007640000000053012544753400022534 0ustar pravipravimodule Doorkeeper module Models module Scopes def scopes OAuth::Scopes.from_string(self[:scopes]) end def scopes_string self[:scopes] end def includes_scope?(*required_scopes) required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) } end end end end doorkeeper-2.2.1/lib/doorkeeper/server.rb0000644000076400007640000000234412544753400017456 0ustar pravipravimodule Doorkeeper class Server attr_accessor :context def initialize(context = nil) @context = context end def authorization_request(strategy) klass = Request.authorization_strategy strategy klass.build self end def token_request(strategy) klass = Request.token_strategy strategy klass.build self end # TODO: context should be the request def parameters context.request.parameters end def client @client ||= OAuth::Client.authenticate(credentials) end def client_via_uid @client_via_uid ||= OAuth::Client.find(parameters[:client_id]) end def current_resource_owner context.send :current_resource_owner end def current_refresh_token AccessToken.by_refresh_token(parameters[:refresh_token]) end def grant AccessGrant.by_token(parameters[:code]) end # TODO: Use configuration and evaluate proper context on block def resource_owner context.send :resource_owner_from_credentials end def credentials methods = Doorkeeper.configuration.client_credentials_methods @credentials ||= OAuth::Client::Credentials.from_request(context.request, *methods) end end end doorkeeper-2.2.1/lib/doorkeeper/grape/0000755000076400007640000000000012544753400016716 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/grape/authorization_decorator.rb0000644000076400007640000000057212544753400024211 0ustar pravipravimodule Doorkeeper module Grape class AuthorizationDecorator < SimpleDelegator def parameters params end def authorization env = __getobj__.env env['HTTP_AUTHORIZATION'] || env['X-HTTP_AUTHORIZATION'] || env['X_HTTP_AUTHORIZATION'] || env['REDIRECT_X_HTTP_AUTHORIZATION'] end end end end doorkeeper-2.2.1/lib/doorkeeper/grape/helpers.rb0000644000076400007640000000236712544753400020715 0ustar pravipravirequire 'doorkeeper/grape/authorization_decorator' module Doorkeeper module Grape module Helpers extend ::Grape::API::Helpers include Doorkeeper::Rails::Helpers # endpoint specific scopes > parameter scopes > default scopes def doorkeeper_authorize!(*scopes) endpoint_scopes = env['api.endpoint'].options[:route_options][:scopes] scopes = if endpoint_scopes Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes) elsif scopes && !scopes.empty? Doorkeeper::OAuth::Scopes.from_array(scopes) end super(*scopes) end def doorkeeper_render_error_with(error) status_code = case error.status when :unauthorized 401 when :forbidden 403 end error!({ error: error.description }, status_code) end private def doorkeeper_token @_doorkeeper_token ||= OAuth::Token.authenticate( decorated_request, *Doorkeeper.configuration.access_token_methods ) end def decorated_request AuthorizationDecorator.new(request) end end end end doorkeeper-2.2.1/lib/doorkeeper/generators/0000755000076400007640000000000012544753400017771 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/generators/doorkeeper/0000755000076400007640000000000012544753400022130 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/generators/doorkeeper/mongo_mapper/0000755000076400007640000000000012544753400024613 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/generators/doorkeeper/mongo_mapper/indexes_generator.rb0000644000076400007640000000050612544753400030646 0ustar pravipravimodule Doorkeeper module MongoMapper class IndexesGenerator < ::Rails::Generators::Base source_root File.expand_path('templates', __FILE__) desc "'Creates an indexes file for use with MongoMapper's rake db:index'" def install template 'indexes.rb', 'db/indexes.rb' end end end end doorkeeper-2.2.1/lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/0000755000076400007640000000000012544753400026611 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/indexes.rb0000644000076400007640000000016512544753400030577 0ustar pravipraviDoorkeeper::Application.create_indexes Doorkeeper::AccessGrant.create_indexes Doorkeeper::AccessToken.create_indexes doorkeeper-2.2.1/lib/doorkeeper/rails/0000755000076400007640000000000012544753400016732 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/rails/routes/0000755000076400007640000000000012544753400020253 5ustar pravipravidoorkeeper-2.2.1/lib/doorkeeper/rails/routes/mapping.rb0000644000076400007640000000155412544753400022240 0ustar pravipravimodule Doorkeeper module Rails class Routes class Mapping attr_accessor :controllers, :as, :skips def initialize @controllers = { authorizations: 'doorkeeper/authorizations', applications: 'doorkeeper/applications', authorized_applications: 'doorkeeper/authorized_applications', tokens: 'doorkeeper/tokens', token_info: 'doorkeeper/token_info' } @as = { authorizations: :authorization, tokens: :token, token_info: :token_info } @skips = [] end def [](routes) { controllers: @controllers[routes], as: @as[routes] } end def skipped?(controller) @skips.include?(controller) end end end end end doorkeeper-2.2.1/lib/doorkeeper/rails/routes/mapper.rb0000644000076400007640000000112312544753400022061 0ustar pravipravimodule Doorkeeper module Rails class Routes class Mapper def initialize(mapping = Mapping.new) @mapping = mapping end def map(&block) self.instance_eval(&block) if block @mapping end def controllers(controller_names = {}) @mapping.controllers.merge!(controller_names) end def skip_controllers(*controller_names) @mapping.skips = controller_names end def as(alias_names = {}) @mapping.as.merge!(alias_names) end end end end end doorkeeper-2.2.1/lib/doorkeeper/rails/routes.rb0000644000076400007640000000475712544753400020615 0ustar pravipravirequire 'doorkeeper/rails/routes/mapping' require 'doorkeeper/rails/routes/mapper' module Doorkeeper module Rails class Routes module Helper # TODO: options hash is not being used def use_doorkeeper(options = {}, &block) Doorkeeper::Rails::Routes.new(self, &block).generate_routes!(options) end end def self.install! ActionDispatch::Routing::Mapper.send :include, Doorkeeper::Rails::Routes::Helper end attr_accessor :routes def initialize(routes, &block) @routes, @block = routes, block end def generate_routes!(options) @mapping = Mapper.new.map(&@block) routes.scope options[:scope] || 'oauth', as: 'oauth' do map_route(:authorizations, :authorization_routes) map_route(:tokens, :token_routes) map_route(:tokens, :revoke_routes) map_route(:applications, :application_routes) map_route(:authorized_applications, :authorized_applications_routes) map_route(:token_info, :token_info_routes) end end private def map_route(name, method) unless @mapping.skipped?(name) send method, @mapping[name] end end def authorization_routes(mapping) routes.resource( :authorization, path: 'authorize', only: [:create, :destroy], as: mapping[:as], controller: mapping[:controllers] ) do routes.get '/:code', action: :show, on: :member routes.get '/', action: :new, on: :member end end def token_routes(mapping) routes.resource( :token, path: 'token', only: [:create], as: mapping[:as], controller: mapping[:controllers] ) end def revoke_routes(mapping) routes.post 'revoke', controller: mapping[:controllers], action: :revoke end def token_info_routes(mapping) routes.resource( :token_info, path: 'token/info', only: [:show], as: mapping[:as], controller: mapping[:controllers] ) end def application_routes(mapping) routes.resources :doorkeeper_applications, controller: mapping[:controllers], as: :applications, path: 'applications' end def authorized_applications_routes(mapping) routes.resources :authorized_applications, only: [:index, :destroy], controller: mapping[:controllers] end end end end doorkeeper-2.2.1/lib/doorkeeper/rails/helpers.rb0000644000076400007640000000460612544753400020727 0ustar pravipravimodule Doorkeeper module Rails module Helpers extend ActiveSupport::Concern def doorkeeper_authorize!(*scopes) @_doorkeeper_scopes = scopes.presence || Doorkeeper.configuration.default_scopes if !valid_doorkeeper_token? doorkeeper_render_error end end def doorkeeper_unauthorized_render_options nil end def doorkeeper_forbidden_render_options nil end def valid_doorkeeper_token? doorkeeper_token && doorkeeper_token.acceptable?(@_doorkeeper_scopes) end private def doorkeeper_render_error error = doorkeeper_error headers.merge! error.headers.reject { |k| "Content-Type" == k } doorkeeper_render_error_with(error) end def doorkeeper_render_error_with(error) options = doorkeeper_render_options || {} if options.blank? head error.status else options[:status] = error.status options[:layout] = false if options[:layout].nil? render options end end def doorkeeper_error if doorkeeper_invalid_token_response? OAuth::InvalidTokenResponse.from_access_token(doorkeeper_token) else OAuth::ForbiddenTokenResponse.from_scopes(@_doorkeeper_scopes) end end def doorkeeper_render_options if doorkeeper_invalid_token_response? doorkeeper_unauthorized_render_options else doorkeeper_forbidden_render_options end end def doorkeeper_invalid_token_response? !doorkeeper_token || !doorkeeper_token.accessible? end def doorkeeper_token @_doorkeeper_token ||= OAuth::Token.authenticate( request, *Doorkeeper.configuration.access_token_methods ) end module ClassMethods def doorkeeper_for(*_args) fail( Errors::DoorkeeperError, "`doorkeeper_for` no longer available", <<-eos \nStarting in version 2.0.0 of doorkeeper gem, `doorkeeper_for` is no longer available. Please change `doorkeeper_for` calls in your application with: before_action :doorkeeper_authorize! For more information check the README: https://github.com/doorkeeper-gem/doorkeeper#protecting-resources-with-oauth-aka-your-api-endpoint\n eos ) end end end end end doorkeeper-2.2.1/gemfiles/0000755000076400007640000000000012544753400014506 5ustar pravipravidoorkeeper-2.2.1/gemfiles/Gemfile.mongoid2.rb0000644000076400007640000000016512544753400020122 0ustar pravipravigemfile = 'gemfiles/Gemfile.common.rb' instance_eval IO.read(gemfile), gemfile gem 'mongoid', '~> 2' gem 'bson_ext' doorkeeper-2.2.1/gemfiles/Gemfile.mongo_mapper.rb0000644000076400007640000000016212544753400021064 0ustar pravipravigemfile = 'gemfiles/Gemfile.common.rb' instance_eval IO.read(gemfile), gemfile gem 'mongo_mapper' gem 'bson_ext' doorkeeper-2.2.1/gemfiles/Gemfile.mongoid3.rb0000644000076400007640000000014612544753400020122 0ustar pravipravigemfile = 'gemfiles/Gemfile.common.rb' instance_eval IO.read(gemfile), gemfile gem 'mongoid', '~> 3' doorkeeper-2.2.1/gemfiles/Gemfile.common.rb0000644000076400007640000000016012544753400017667 0ustar pravipraviENV['rails'] ||= '4.2.0' source 'https://rubygems.org' gem 'rails', "~> #{ENV['rails']}" gemspec path: '../' doorkeeper-2.2.1/gemfiles/Gemfile.mongoid4.rb0000644000076400007640000000014612544753400020123 0ustar pravipravigemfile = 'gemfiles/Gemfile.common.rb' instance_eval IO.read(gemfile), gemfile gem 'mongoid', '~> 4' doorkeeper-2.2.1/Rakefile0000644000076400007640000000063412544753400014363 0ustar pravipravirequire 'bundler/setup' require 'rspec/core/rake_task' desc 'Default: run specs.' task :default => :spec desc "Run all specs" RSpec::Core::RakeTask.new(:spec) do |config| config.verbose = false end namespace :doorkeeper do desc "Install doorkeeper in dummy app" task :install do cd 'spec/dummy' system 'bundle exec rails g doorkeeper:install --force' end end Bundler::GemHelper.install_tasks doorkeeper-2.2.1/MIT-LICENSE0000644000076400007640000000205712544753400014353 0ustar pravipraviCopyright 2011 Applicake. http://applicake.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. doorkeeper-2.2.1/NEWS.md0000644000076400007640000004255212544753400014021 0ustar pravipravi# News User-visible changes worth mentioning. --- ## 2.2.1 - [#636] `custom_access_token_expires_in` bugfixes - [#641] syntax error fix (Issue #612) - [#633] Send extra details to Custom Token Generator - [#628] Refactor: improve orm adapters to ease extension - [#637] Upgrade to rspec to 3.2 ## 2.2.0 - 2015-04-19 - [#611] Allow custom access token generators to be used - [#632] Properly fallback to `default_scopes` when no scope is specified - [#622] Clarify that there is a logical OR between scopes for authorizing - [#635] Upgrade to rspec 3 - [#627] i18n fallbacks to english - Moved CHANGELOG to NEWS.md ## 2.1.4 - 2015-03-27 - [#595] HTTP spec: Add `scope` for refresh token scope param - [#596] Limit scopes in app scopes for client credentials - [#567] Add Grape helpers for easier integration with Grape framework - [#606] Add custom access token expiration support for Client Credentials flow ## 2.1.3 - 2015-03-01 - [#588] Fixes scopes_match? bug that skipped authorization form in some cases ## 2.1.2 - 2015-02-25 - [#574] Remove unused update authorization route. - [#576] Filter out sensitive parameters from logs. - [#582] The Authorization HTTP header fields are now case insensitive. - [#583] Database connection bugfix in certain scenarios. - Testing improvements ## 2.1.1 - 2015-02-06 - Remove `wildcard_redirect_url` option - [#481] Customize token flow OAuth expirations with a config lambda - [#568] TokensController: Memoize strategy.authorize_response result to enable subclasses to use the response object. - [#571] Fix database initialization issues in some configurations. - Documentation improvements ## 2.1.0 - 2015-01-13 - [#540] Include `created_at` in response. - [#538] Check application-level scopes in client_credentials and password flow. - [5596227] Check application scopes in AccessToken when present. Fixes a bug in doorkeeper 2.0.0 and 2.0.1 referring to application specific scopes. - [#534] Internationalizes doorkeeper views. - [#545] Ensure there is a connection to the database before checking for missing columns - [#546] Use `Doorkeeper::` prefix when referencing `Application` to avoid possible application model name conflict. - [#538] Test with Rails ~> 4.2. ### Potentially backward incompatible changes - Enable by default `authorization_code` and `client_credentials` grant flows. Disables implicit and password grant flows by default. - [#510, #544, 722113f] Revoked refresh token response bugfix. ## 2.0.1 - 2014-12-17 - [#525, #526, #527] Fix `ActiveRecord::NoDatabaseError` on gem load. ## 2.0.0 - 2014-12-16 ### Backward incompatible changes - [#448] Removes `doorkeeper_for` helper. Now we use `before_action :doorkeeper_authorize!`. - [#469] Allow client applications to restrict the set of allowable scopes. Fixes #317. `oauth_applications` relation needs a new `scopes` string column, non nullable, which defaults to an empty string. To add the column run: ``` rails generate doorkeeper:application_scopes ``` If you’d rather do it by hand, your ActiveRecord migration should contain: ```ruby add_column :oauth_applications, :scopes, :string, null: false, default: ‘’ ``` ### Removed deprecations - Removes `test_redirect_uri` option. It is now called `native_redirect_uri`. - [#446] Removes `mount Doorkeeper::Engine`. Now we use `use_doorkeeper`. ### Others - [#484] Performance improvement - avoid performing order_by when not required. - [#450] When password is invalid in Password Credentials Grant, Doorkeeper returned 'invalid_resource_owner' instead of 'invalid_grant', as the spec declares. Fixes #444. - [#452] Allows `revoked_at` to be set in the future, for future expiry. Rationale: https://github.com/doorkeeper-gem/doorkeeper/pull/452#issuecomment-51431459 - [#480] For Implicit grant flow, access tokens can now be reused. Fixes #421. - [#491] Reworks of @jasl's #454 and #478. ORM refactor that allows doorkeeper to be extended more easily with unsupported ORMs. It also marks the boundaries between shared model code and ORM specifics inside of the gem. - [#496] Tests with Rails 4.2. - [#489] Adds `force_ssl_in_redirect_uri` to force the usage of the HTTPS protocol in non-native redirect uris. - [#516] SECURITY: Adds `protect_from_forgery` to `Doorkeeper::ApplicationController` - [#518] Fix random failures in mongodb. --- ## 1.4.2 - 2015-03-02 - [#576] Filter out sensitive parameters from logs ## 1.4.1 - 2014-12-17 - [#516] SECURITY: Adds `protect_from_forgery` to `Doorkeeper::ApplicationController` ## 1.4.0 - 2014-07-31 - internals - [#427] Adds specs expectations. - [#428] Error response refactor. - [#417] Moves token validation into Access Token class. - [#439] Removes redundant module includes. - [#443] TokensController and TokenInfoController inherit from ActionController::Metal - bug - [#418] fixes #243, requests with insufficient scope now respond 403 instead of 401. (API change) - [#438] fixes #398, native redirect for implicit token grant bug. - [#440] namespace fixes - enhancements - [#432] Keeps query parameters ## 1.3.1 - 2014-07-06 - enhancements - [#405] Adds facade to more easily get the token from a request in a route constraint. - [#415] Extend Doorkeeper TokenResponse with an `after_successful_response` callback that allows handling of `response` object. - internals - [#409] Deprecates `test_redirect_uri` in favor of `native_redirect_uri`. See discussion in: [#351]. - [#411] Clean rspec deprecations. General test improvements. - [#412] rspec line width can go longer than 80 (hound CI config). - bug - [#413] fixes #340, routing scope is now taken into account in redirect. - [#401] and [#425] application is not required any longer for access_token. ## 1.3.0 - 2014-05-23 - enhancements - [#387] Adds reuse_access_token configuration option. ## 1.2.0 - 2014-05-02 - enhancements - [#376] Allow users to enable basic header authorization for access tokens. - [#374] Token revocation implementation [RFC 7009] - [#295] Only enable specific grant flows. - internals - [#381] Locale source fix. - [#380] Renames `errors_for` to `doorkeeper_errors_for`. - [#390] Style adjustments in accordance with Ruby Style Guide form Thoughtbot. ## 1.1.0 - 2014-03-29 - enhancements - [#336] mongoid4 support. - [#372] Allow users to set ActiveRecord table_name_prefix/suffix options - internals - [#343] separate OAuth's admin and user end-point to different layouts, upgrade theme to Bootstrap 3.1. - [#348] Move render_options in filter after `@error` has been set ## 1.0.0 - 2014-01-13 - bug (spec) - [#228] token response `expires_in` value is now in seconds, relative to request time - [#296] client is optional for password grant type. - [#319] If client credentials are present on password grant type they are validated - [#326] If client credentials are present in refresh token they are validated - [#326] If authenticated client does not match original client that obtained a refresh token it responds `invalid_grant` instead of `invalid_client`. Previous usage was invalid according to Section 5.2 of the spec. - [#329] access tokens' `scopes` string wa being compared against `default_scopes` symbols, always unauthorizing. - [#318] Include "WWW-Authenticate" header with Unauthorized responses - enhancements - [#293] Adds ActionController::Instrumentation in TokensController - [#298] Support for multiple redirect_uris added. - [#313] `AccessToken.revoke_all_for` actually revokes all non-revoked tokens for an application/owner instead of deleting them. - [#333] Rails 4.1 support - internals - Removes jQuery dependency [fixes #300] [PR #312 is related] - [#294] Client uid and secret will be generated only if not present. - [#316] Test warnings addressed. - [#338] Rspec 3 syntax. --- ## 0.7.4 - 2013-12-01 - bug - Symbols instead of strings for user input. ## 0.7.3 - 2013-10-04 - enhancements - [#204] Allow to overwrite scope in routes - internals - Returns only present keys in Token Response (may imply a backwards incompatible change). https://github.com/doorkeeper-gem/doorkeeper/issues/220 - bug - [#290] Support for Rails 4 when 'protected_attributes' gem is present. ## 0.7.2 - 2013-09-11 - enhancements - [#272] Allow issuing multiple access_tokens for one user/application for multiple devices - [#170] Increase length of allowed redirect URIs - [#239] Do not try to load unavailable Request class for the current phase. - [#273] Relax jquery-rails gem dependency ## 0.7.1 - 2013-08-30 - bug - [#269] Rails 3.2 raised `ActiveModel::MassAssignmentSecurity::Error`. ## 0.7.0 - 2013-08-21 - enhancements - [#229] Rails 4! - internals - [#203] Changing table name to be specific in column_names_with_table - [#215] README update - [#227] Use Rails.config.paths["config/routes"] instead of assuming "config/routes.rb" exists - [#262] Add jquery as gem dependency - [#263] Add a configuration for ActiveRecord.establish_connection - Deprecation and Ruby warnings (PRs merged outside of GitHub). ## 0.6.7 - 2013-01-13 - internals - [#188] Add IDs to the show views for integration testing [@egtann](https://github.com/egtann) ## 0.6.6 - 2013-01-04 - enhancements - [#187] Raise error if configuration is not set ## 0.6.5 - 2012-12-26 - enhancements - [#184] Vendor the Bootstrap CSS [@tylerhunt](https://github.com/tylerhunt) ## 0.6.4 - 2012-12-15 - bug - [#180] Add localization to authorized_applications destroy notice [@aalvarado](https://github.com/aalvarado) ## 0.6.3 - 2012-12-07 - bugfixes - [#163] Error response content-type header should be application/json [@ggayan](https://github.com/ggayan) - [#175] Make token.expires_in_seconds return nil when expires_in is nil [@miyagawa](https://github.com/miyagawa) - enhancements - [#166, #172, #174] Behavior to automatically authorize based on a configured proc - internals - [#168] Using expectation syntax for controller specs [@rdsoze](https://github.com/rdsoze) ## 0.6.2 - 2012-11-10 - bugfixes - [#162] Remove ownership columns from base migration template [@rdsoze](https://github.com/rdsoze) ## 0.6.1 - 2012-11-07 - bugfixes - [#160] Removed |routes| argument from initializer authenticator blocks - documentation - [#160] Fixed description of context of authenticator blocks ## 0.6.0 - 2012-11-05 - enhancements - Mongoid `orm` configuration accepts only :mongoid2 or :mongoid3 - Authorization endpoint does not redirect in #new action anymore. It wasn't specified by OAuth spec - TokensController now inherits from ActionController::Metal. There might be performance upgrades - Add link to authorization in Applications scaffold - [#116] MongoMapper support [@carols10cents](https://github.com/carols10cents) - [#122] Mongoid3 support [@petergoldstein](https://github.com/petergoldstein) - [#150] Introduce test redirect uri for applications - bugfixes - [#157] Response token status should be `:ok`, not `:success` [@theycallmeswift](https://github.com/theycallmeswift) - [#159] Remove ActionView::Base.field_error_proc override (fixes #145) - internals - Update development dependencies - Several refactorings - Rails/ORM are easily swichable with env vars (rails and orm) - Travis now tests against Mongoid v2 ## 0.5.0 - 2012-10-20 Official support for rubinius was removed. - enhancements - Configure the way access token is retrieved from request (default to bearer header) - Authorization Code expiration time is now configurable - Add support for mongoid - [#78, #128, #137, #138] Application Ownership - [#92] Allow users to skip controllers - [#99] Remove deprecated warnings for data-* attributes [@towerhe](https://github.com/towerhe) - [#101] Return existing access_token for PasswordAccessTokenRequest [@benoist](https://github.com/benoist) - [#104] Changed access token scopes example code to default_scopes and optional_scopes [@amkirwan](https://github.com/amkirwan) - [#107] Fix typos in initializer - [#123] i18n for validator, flash messages [@petergoldstein](https://github.com/petergoldstein) - [#140] ActiveRecord is the default value for the ORM [@petergoldstein](https://github.com/petergoldstein) - internals - [#112, #120] Replacing update_attribute with update_column to eliminate deprecation warnings [@rmoriz](https://github.com/rmoriz), [@petergoldstein](https://github.com/petergoldstein) - [#121] Updating all development dependencies to recent versions. [@petergoldstein](https://github.com/petergoldstein) - [#144] Adding MongoDB dependency to .travis.yml [@petergoldstein](https://github.com/petergoldstein) - [#143] Displays errors for unconfigured error messages [@timgaleckas](https://github.com/timgaleckas) - bugfixes - [#102] Not returning 401 when access token generation fails [@cslew](https://github.com/cslew) - [#125] Doorkeeper is using ActiveRecord version of as_json in ORM agnostic code [@petergoldstein](https://github.com/petergoldstein) - [#142] Prevent double submission of password based authentication [@bdurand](https://github.com/bdurand) - documentation - [#141] Add rack-cors middleware to readme [@gottfrois](https://github.com/gottfrois) ## 0.4.2 - 2012-06-05 - bugfixes: - [#94] Uninitialized Constant in Password Flow ## 0.4.1 - 2012-06-02 - enhancements: - Backport: Move doorkeeper_for extension to Filter helper ## 0.4.0 - 2012-05-26 - deprecation - Deprecate authorization_scopes - database changes - AccessToken#resource_owner_id is not nullable - enhancements - [#83] Add Resource Owner Password Credentials flow [@jaimeiniesta](https://github.com/jaimeiniesta) - [#76] Allow token expiration to be disabled [@mattgreen](https://github.com/mattgreen) - [#89] Configure the way client credentials are retrieved from request - [#b6470a] Add Client Credentials flow - internals - [#2ece8d, #f93778] Introduce Client and ErrorResponse classes ## 0.3.4 - 2012-05-24 - Fix attr_accessible for rails 3.2.x ## 0.3.3 - 2012-05-07 - [#86] shrink gem package size ## 0.3.2 - 2012-04-29 - enhancements - [#54] Ignore Authorization: headers that are not Bearer [@miyagawa](https://github.com/miyagawa) - [#58, #64] Add destroy action to applications endpoint [@jaimeiniesta](https://github.com/jaimeiniesta), [@davidfrey](https://github.com/davidfrey) - [#63] TokensController responds with `401 unauthorized` [@jaimeiniesta](https://github.com/jaimeiniesta) - [#67, #72] Fix for mass-assignment [@cicloid](https://github.com/cicloid) - internals - [#49] Add Gemnasium status image to README [@laserlemon](https://github.com/laserlemon) - [#50] Fix typos [@tomekw](https://github.com/tomekw) - [#51] Updated the factory_girl_rails dependency, fix expires_in response which returned a float number instead of integer [@antekpiechnik](https://github.com/antekpiechnik) - [#62] Typos, .gitignore [@jaimeiniesta](https://github.com/jaimeiniesta) - [#65] Change _path redirections to _url redirections [@jaimeiniesta](https://github.com/jaimeiniesta) - [#75] Fix unknown method #authenticate_admin! [@mattgreen](https://github.com/mattgreen) - Remove application link in authorized app view ## 0.3.1 - 2012-02-17 - enhancements - [#48] Add if, else options to doorkeeper_for - Add views generator - internals - Namespace models ## 0.3.0 - 2012-02-11 - enhancements - [#17, #31] Add support for client credentials in basic auth header [@GoldsteinTechPartners](https://github.com/GoldsteinTechPartners) - [#28] Add indices to migration [@GoldsteinTechPartners](https://github.com/GoldsteinTechPartners) - [#29] Allow doorkeeper to run with rails 3.2 [@john-griffin](https://github.com/john-griffin) - [#30] Improve client's redirect uri validation [@GoldsteinTechPartners](https://github.com/GoldsteinTechPartners) - [#32] Add token (implicit grant) flow [@GoldsteinTechPartners](https://github.com/GoldsteinTechPartners) - [#34] Add support for custom unathorized responses [@GoldsteinTechPartners](https://github.com/GoldsteinTechPartners) - [#36] Remove repetitions from the Authorised Applications view [@carvil](https://github.com/carvil) - When user revoke an application, all tokens for that application are revoked - Error messages now can be translated - Install generator copies the error messages localization file - internals - Fix deprecation warnings in ActiveSupport::Base64 - Remove deprecation in doorkeeper_for that handles hash arguments - Depends on railties instead of whole rails framework - CI now integrates with rails 3.1 and 3.2 ## 0.2.0 - 2011-12-17 - enhancements - [#4] Add authorized applications endpoint - [#5, #11] Add access token scopes - [#10] Add access token expiration by default - [#9, #12] Add refresh token flow - internals - [#7] Improve configuration options with :default - Improve configuration options with :builder - Refactor config class - Improve coverage of authorization request integration - bug fixes - [#6, #20] Fix access token response headers - Fix issue with state parameter - deprecation - deprecate :only and :except options in doorkeeper_for ## 0.1.1 - 2011-11-30 - enhancements - [#3] Authorization code must be short lived and single use - [#2] Improve views provided by doorkeeper - [#1] Skips authorization form if the client has been authorized by the resource owner - Improve readme - bugfixes - Fix issue when creating the access token (wrong client id) ## 0.1.0 - 2011-11-25 - Authorization Code flow - OAuth applications endpoint doorkeeper-2.2.1/.gitignore0000644000076400007640000000024412544753400014703 0ustar pravipravi.bundle/ .rbx *.rbc log/*.log pkg/ spec/dummy/db/*.sqlite3 spec/dummy/log/*.log spec/dummy/tmp/ Gemfile.lock gemfiles/*.lock spec/generators/tmp .rvmrc *.swp .idea