diff --git a/Gemfile b/Gemfile index c36b3e8..89bc3c9 100644 --- a/Gemfile +++ b/Gemfile @@ -114,3 +114,13 @@ gem "font-awesome-rails" gem "sprockets", '3.6.3' #gem "activemodel-serializers-xml" + +# Authentication against Google, Facebook and others +gem 'omniauth' +gem 'omniauth-amazon' +gem 'omniauth-google-oauth2' +gem 'omniauth-github' +gem 'omniauth-twitter' +gem 'omniauth-facebook' +# gem 'omniauth-launchpad' # is broken +gem 'omniauth-launchpad', :git => 'https://github.com/joaopapereira/omniauth-launchpad' diff --git a/README.developer.md b/README.developer.md new file mode 100644 index 0000000..e3d20a8 --- /dev/null +++ b/README.developer.md @@ -0,0 +1,38 @@ +# Authentication + +The application uses _omniauth_ to allow local authentication for moderators +and adds OAuth authentication to connect to Google+, Github and other +authentication providers. + +Documentation on omniauth: + +https://github.com/omniauth/omniauth/wiki/List-of-Strategies +https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview + +## Google+ + +The client ID for the debshots application is: + + 398593918966-0fpmit0pb6ptio1ndsie5dfcnqhei63l.apps.googleusercontent.com + +The private key is: + + uRQq_dLs1kx7l5sYIyEyPVRc + +(This information is connected to the christoph.haas@gmail.com account.) + +## Amazon + +## launchpad + +## Github + +## Caveats + +The OAuth callback handling uses Ruby's "faraday" library. Unfortunately +Faraday may easily miss the directory where the common CAs are stored. +So the path to the certificates on the system needs to be provided: + + config.omniauth :google_oauth2, '398593918966-0fpmit0pb6ptio1ndsie5dfcnqhei63l.apps.googleusercontent.com', 'uRQq_dLs1kx7l5sYIyEyPVRc', :client_options => {:ssl => {:ca_path => '/etc/ssl/certs'}} + +For another explanation of the issue see: https://gist.github.com/kt103099/3183125 diff --git a/app/models/user.rb b/app/models/user.rb index 3e194d8..87531a8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,11 +2,38 @@ class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, - # :registerable, - # :recoverable, + :registerable, + :recoverable, # :rememberable, :trackable, :validatable, :timeoutable, - :lockable + :lockable, + :omniauthable, :omniauth_providers => [:google_oauth2, :launchpad] + # :omniauthable, :omniauth_providers => [:launchpad, :google] + + + def self.from_omniauth(auth) + where(provider: auth.provider, uid: auth.uid).first_or_create do |user| + user.provider = auth.provider + user.uid = auth.uid + user.email = auth.info.email + user.password = Devise.friendly_token[0,20] + end + end + # + # def self.from_omniauth(access_token) + # data = access_token.info + # user = User.where(:email => data["email"]).first + # + # # Uncomment the section below if you want users to be created if they don't exist + # # unless user + # # user = User.create(name: data["name"], + # # email: data["email"], + # # password: Devise.friendly_token[0,20] + # # ) + # # end + # user + # end + end diff --git a/app/views/devise/sessions/new.slim b/app/views/devise/sessions/new.slim index 6f700c3..5a6cc93 100644 --- a/app/views/devise/sessions/new.slim +++ b/app/views/devise/sessions/new.slim @@ -20,12 +20,20 @@ .small-6.columns = f.password_field :password, autocomplete: "off" - - if devise_mapping.rememberable? - .small-6.columns - = f.check_box :remember_me - .small-6.columns - = f.label :remember_me + / - if devise_mapping.rememberable? + / .small-6.columns + / = f.check_box :remember_me + / .small-6.columns + / = f.label :remember_me = f.submit "Log in", class: 'button' - = render "devise/shared/links" + / = render "devise/shared/links" + +/ h1 Experimental SSL certificate Debian SSO auth +/ +/ = link_to 'log in using your secure certificate', users_debian_sso_path + +/ = link_to "Sign in with Launchpad", user_launchpad_omniauth_authorize_path += link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path += link_to "Sign in with Launchpad", user_launchpad_omniauth_authorize_path diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 49b1543..cac79ae 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -4,19 +4,22 @@ Devise.setup do |config| # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. - # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key` + # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. - # config.secret_key = 'aee58a36ef657d7d3f9d2e0a94696a292b6e86a9143e28ccf92aede43f92cdf4deefaadc96d663b2e911962e8d5efd1bceb9095b9bbb9186be3b268e98ed8f02' + # config.secret_key = '7124681eb3be46bd68df035f39e47f46c8456276a0ee51989eb3a29a2f3e90b227b079ce54e166eee1599ac3ebf6b72ab073f4dcb74685336241b698f0ca7800' # ==> Mailer Configuration # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - config.mailer_sender = 'webmaster@screenshots.debian.net' + config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' # Configure the class responsible to send e-mails. # config.mailer = 'Devise::Mailer' + # Configure the parent class responsible to send e-mails. + # config.parent_mailer = 'ActionMailer::Base' + # ==> ORM configuration # Load and configure the ORM. Supports :active_record (default) and # :mongoid (bson_ext recommended) by default. Other ORMs may be @@ -87,19 +90,25 @@ Devise.setup do |config| # from the server. You can disable this option at your own risk. # config.clean_up_csrf_token_on_authentication = true + # When false, Devise will not attempt to reload routes on eager load. + # This can reduce the time taken to boot the app but if your application + # requires the Devise mappings to be loaded during boot time the application + # won't boot properly. + # config.reload_routes = true + # ==> Configuration for :database_authenticatable - # For bcrypt, this is the cost for hashing the password and defaults to 10. If - # using other encryptors, it sets how many times you want the password re-encrypted. + # For bcrypt, this is the cost for hashing the password and defaults to 11. If + # using other algorithms, it sets how many times you want the password to be hashed. # # Limiting the stretches to just one in testing will increase the performance of # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use # a value less than 10 in other environments. Note that, for bcrypt (the default - # encryptor), the cost increases exponentially with the number of stretches (e.g. + # algorithm), the cost increases exponentially with the number of stretches (e.g. # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). - config.stretches = Rails.env.test? ? 1 : 10 + config.stretches = Rails.env.test? ? 1 : 11 - # Setup a pepper to generate the encrypted password. - # config.pepper = '0a418c1302e92349fea48356135f06555300bf9cb0edc745abf5bac5239953135c43bee31491c20a7f5e83023936d0c0e33ada8275ba285870a81ced2d223eed' + # Set up a pepper to generate the hashed password. + # config.pepper = '28cbda9dffa4952d8234ceb9a2e98e804c349d010c9ca90139d6401eaccb5a76f7fa77fa5162483ae67db6d6fbb3535e2ec62d850b35742e8dd1c3ea5a4a460c' # Send a notification email when the user's password is changed # config.send_password_change_notification = false @@ -145,12 +154,12 @@ Devise.setup do |config| # ==> Configuration for :validatable # Range for password length. - config.password_length = 8..72 + config.password_length = 6..128 # Email regex used to validate email formats. It simply asserts that # one (and only one) @ exists in the given string. This is mainly # to give user feedback and not to assert the e-mail validity. - # config.email_regexp = /\A[^@]+@[^@]+\z/ + config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ # ==> Configuration for :timeoutable # The time you want to timeout the user session without activity. After this @@ -165,22 +174,6 @@ Devise.setup do |config| # Defines which key will be used when locking and unlocking an account # config.unlock_keys = [:email] - # Defines which strategy will be used to lock an account. - config.lock_strategy = :failed_attempts - - # Defines which key will be used when locking and unlocking an account - config.unlock_keys = [ :time ] - - # Defines which strategy will be used to unlock an account. - # :time = Re-enables login after a certain amount of time (see :unlock_in below) - config.unlock_strategy = :time - - # Number of authentication tries before locking an account if lock_strategy - # is failed attempts. - config.maximum_attempts = 10 - - # Time interval to unlock the account if :time is enabled as unlock_strategy. - config.unlock_in = 1.hours # Defines which strategy will be used to unlock an account. # :email = Sends an unlock link to the user email @@ -214,11 +207,11 @@ Devise.setup do |config| # config.sign_in_after_reset_password = true # ==> Configuration for :encryptable - # Allow you to use another encryption algorithm besides bcrypt (default). You can use - # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, - # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) - # and :restful_authentication_sha1 (then you should set stretches to 10, and copy - # REST_AUTH_SITE_KEY to pepper). + # Allow you to use another hashing or encryption algorithm besides bcrypt (default). + # You can use :sha1, :sha512 or algorithms from others authentication tools as + # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20 + # for default behavior) and :restful_authentication_sha1 (then you should set + # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper). # # Require the `devise-encryptable` gem when using anything other than bcrypt # config.encryptor = :sha512 @@ -278,4 +271,11 @@ Devise.setup do |config| # When using OmniAuth, Devise cannot automatically set OmniAuth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' + + # config.omniauth :launchpad, 'debshots' + config.omniauth :google_oauth2, '398593918966-0fpmit0pb6ptio1ndsie5dfcnqhei63l.apps.googleusercontent.com', 'uRQq_dLs1kx7l5sYIyEyPVRc', :client_options => {:ssl => {:ca_path => '/etc/ssl/certs'}} + config.omniauth :launchpad, 'Debian Screenshots', :client_options => {:ssl => {:ca_path => '/etc/ssl/certs'}} + end + +# OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE diff --git a/config/routes.rb b/config/routes.rb index c9f6df3..a599aa5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,23 @@ Debshots::Application.routes.draw do - devise_for :users + + get 'admin/status' + + get 'admin/screenshots' + + get 'admin/integration' + + devise_for :users, controllers: { + registrations: "users/registrations", + passwords: "users/passwords", + omniauth_callbacks: "users/omniauth_callbacks" + } + + # devise_for :users, :controllers => { :omniauth_callbacks => "users" } + #devise_for :users + + # get 'users/debian_sso' + # get "users/callback/:action", :controller => "my" + ##get "packages/index" ##get "packages" => "packages#index" ##get "packages/:page/:display" => "packages#index" @@ -16,7 +34,8 @@ Debshots::Application.routes.draw do get 'packages/list' => 'packages#list', as: :packages_list get 'moderate' => 'moderate#index' get 'logs' => 'logs#index' - get 'my_uploads' => 'packages#my_uploads' + get 'my/index' + get 'my/uploads' get 'package/:name' => 'packages#details', as: :package, name: /[^\/]+/ get 'package_reviews/:name' => 'packages#reviews', as: :package_reviews, name: /[^\/]+/ get 'upload', to: redirect('/packages'), as: :upload_legacy # legacy upload form diff --git a/db/migrate/20170405204143_add_omniauth_to_users.rb b/db/migrate/20170405204143_add_omniauth_to_users.rb new file mode 100644 index 0000000..63c42e4 --- /dev/null +++ b/db/migrate/20170405204143_add_omniauth_to_users.rb @@ -0,0 +1,6 @@ +class AddOmniauthToUsers < ActiveRecord::Migration[5.0] + def change + add_column :users, :provider, :string + add_column :users, :uid, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index d2f77c8..f7310f2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170405144026) do +ActiveRecord::Schema.define(version: 20170405204143) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -76,6 +76,8 @@ ActiveRecord::Schema.define(version: 20170405144026) do t.integer "failed_attempts", default: 0, null: false t.string "unlock_token" t.datetime "locked_at" + t.string "provider" + t.string "uid" t.index ["email"], name: "index_users_on_email", unique: true, using: :btree end