From e6ac4b1dcba764d5c75e3e2e9c713e86b1b5e820 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Sat, 19 Mar 2016 13:28:55 +1100 Subject: [PATCH] make metamaps an oauth provider --- Gemfile | 1 + Gemfile.lock | 3 + config/initializers/doorkeeper.rb | 104 +++++++++++++++ config/locales/doorkeeper.en.yml | 123 ++++++++++++++++++ config/routes.rb | 1 + ...20160318141618_create_doorkeeper_tables.rb | 50 +++++++ db/schema.rb | 42 +++++- 7 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 config/initializers/doorkeeper.rb create mode 100644 config/locales/doorkeeper.en.yml create mode 100644 db/migrate/20160318141618_create_doorkeeper_tables.rb diff --git a/Gemfile b/Gemfile index bf5997af..e0105106 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem 'pg' gem 'pundit' gem 'cancan' gem 'pundit_extra' +gem 'doorkeeper' gem 'formula' gem 'formtastic' gem 'json' diff --git a/Gemfile.lock b/Gemfile.lock index ff5c1317..3a3c763b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,6 +87,8 @@ GEM warden (~> 1.2.3) diff-lcs (1.2.5) docile (1.1.5) + doorkeeper (3.1.0) + railties (>= 3.2) dotenv (2.1.0) erubis (2.7.0) execjs (2.6.0) @@ -270,6 +272,7 @@ DEPENDENCIES delayed_job (~> 4.0.2) delayed_job_active_record (~> 4.0.1) devise + doorkeeper dotenv factory_girl_rails formtastic diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb new file mode 100644 index 00000000..10b9980b --- /dev/null +++ b/config/initializers/doorkeeper.rb @@ -0,0 +1,104 @@ +Doorkeeper.configure do + # Change the ORM that doorkeeper will use (needs plugins) + orm :active_record + + # This block will be called to check whether the resource owner is authenticated or not. + resource_owner_authenticator do + current_user || 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 diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml new file mode 100644 index 00000000..7d2d215d --- /dev/null +++ b/config/locales/doorkeeper.en.yml @@ -0,0 +1,123 @@ +en: + 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.' + + 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' + scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.' + 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' + scopes: 'Scopes' + callback_urls: 'Callback urls' + actions: 'Actions' + + authorizations: + buttons: + authorize: 'Authorize' + deny: 'Deny' + error: + title: 'An error has occurred' + new: + title: 'Authorization 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 authorization required' diff --git a/config/routes.rb b/config/routes.rb index b9be5288..013bcd8b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,6 @@ Metamaps::Application.routes.draw do + use_doorkeeper root to: 'main#home', via: :get get 'request', to: 'main#requestinvite', as: :request diff --git a/db/migrate/20160318141618_create_doorkeeper_tables.rb b/db/migrate/20160318141618_create_doorkeeper_tables.rb new file mode 100644 index 00000000..d89b005c --- /dev/null +++ b/db/migrate/20160318141618_create_doorkeeper_tables.rb @@ -0,0 +1,50 @@ +class 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 + + # If you use a custom token generator you may need to change this column + # from string to text, so that it accepts tokens larger than 255 + # characters. More info on custom token generators in: + # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator + # + # t.text :token, null: false + 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 diff --git a/db/schema.rb b/db/schema.rb index d0381055..1ad745a2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160313003721) do +ActiveRecord::Schema.define(version: 20160318141618) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -132,6 +132,46 @@ ActiveRecord::Schema.define(version: 20160313003721) do t.datetime "aws_icon_updated_at" end + create_table "oauth_access_grants", force: :cascade 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"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree + + create_table "oauth_access_tokens", force: :cascade 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, using: :btree + add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree + add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree + + create_table "oauth_applications", force: :cascade 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", default: "", null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree + create_table "synapses", force: :cascade do |t| t.text "desc" t.text "category"