From c5b56f0f5095414fef0ce1fc6c5905939ca2bc91 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Sep 2017 19:35:06 -0300 Subject: [PATCH] autenticacion --- .rubocop.yml | 2 ++ Gemfile | 4 +++ Gemfile.lock | 20 +++++++++++++ config.ru | 7 +++++ lib/sutty.rb | 25 ++++++++++++++++ lib/sutty/login.rb | 34 ++++++++++++++++++++++ lib/sutty/models/usuaria.rb | 10 +++++++ lib/warden/imap.rb | 57 +++++++++++++++++++++++++++++++++++++ sutty.rb | 4 +++ views/500.haml | 1 + views/index.haml | 3 ++ views/login.haml | 11 +++++++ 12 files changed, 178 insertions(+) create mode 100644 .rubocop.yml create mode 100644 config.ru create mode 100644 lib/sutty.rb create mode 100644 lib/sutty/login.rb create mode 100644 lib/sutty/models/usuaria.rb create mode 100644 lib/warden/imap.rb create mode 100644 sutty.rb create mode 100644 views/500.haml create mode 100644 views/index.haml create mode 100644 views/login.haml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..21f179f0 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,2 @@ +Style/AsciiComments: + Enabled: false diff --git a/Gemfile b/Gemfile index c02ae845..1f26e533 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,11 @@ source 'https://rubygems.org' +gem 'email_address' +gem 'haml' gem 'jekyll' +gem 'rack-flash3' gem 'sinatra' +gem 'sinatra_warden' group :development do gem 'pry' diff --git a/Gemfile.lock b/Gemfile.lock index 6f6d91b9..73a792eb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,8 +6,14 @@ GEM ast (2.3.0) coderay (1.1.2) colorator (1.1.0) + email_address (0.1.3) + netaddr + simpleidn ffi (1.9.18) forwardable-extended (2.6.0) + haml (5.0.1) + temple (>= 0.8.0) + tilt jekyll (3.6.0) addressable (~> 2.4) colorator (~> 1.0) @@ -31,6 +37,7 @@ GEM mercenary (0.3.6) method_source (0.8.2) mustermann (1.0.1) + netaddr (1.5.1) parallel (1.12.0) parser (2.4.0.0) ast (~> 2.2) @@ -42,6 +49,8 @@ GEM method_source (~> 0.8.1) public_suffix (3.0.0) rack (2.0.3) + rack-flash3 (1.0.5) + rack rack-protection (2.0.0) rack rainbow (2.2.2) @@ -65,22 +74,33 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) + simpleidn (0.0.9) sinatra (2.0.0) mustermann (~> 1.0) rack (~> 2.0) rack-protection (= 2.0.0) tilt (~> 2.0) + sinatra_warden (0.3.2) + sinatra (>= 1.0.0) + warden (~> 1.0) + temple (0.8.0) tilt (2.0.8) unicode-display_width (1.3.0) + warden (1.2.7) + rack (>= 1.0) PLATFORMS ruby DEPENDENCIES + email_address + haml jekyll pry + rack-flash3 rubocop sinatra + sinatra_warden BUNDLED WITH 1.15.4 diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..bcb59d8d --- /dev/null +++ b/config.ru @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# require 'rack/protection' +require_relative 'sutty' + +# use Rack::Protection +run Sutty::App diff --git a/lib/sutty.rb b/lib/sutty.rb new file mode 100644 index 00000000..47bca4f5 --- /dev/null +++ b/lib/sutty.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'rack-flash' +require 'sinatra/base' +require 'sinatra_warden' +require_relative 'sutty/login' + +module Sutty + # Sutty + class App < Sinatra::Base + use Rack::Flash + use Sutty::Login + register Sinatra::Warden + + set :root, File.expand_path(File.join(File.dirname(__FILE__), '..')) + + before do + authorize! '/login' + end + + get '/' do + haml :index + end + end +end diff --git a/lib/sutty/login.rb b/lib/sutty/login.rb new file mode 100644 index 00000000..65313b30 --- /dev/null +++ b/lib/sutty/login.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'net/imap' +require 'rack-flash' +require 'sinatra/base' +require 'sinatra_warden' +require_relative '../warden/imap' +require_relative 'models/usuaria' + +module Sutty + # Login + class Login < Sinatra::Base + use Rack::Flash + register Sinatra::Warden + + enable :sessions + enable :logging + enable :auth_use_referrer + + # Configura Warden para usar la estrategia IMAP y obtener la cuenta + # de usuaria a partir de la cookie. + use Warden::Manager do |config| + config.default_scope = :user + config.scope_defaults :user, strategies: [:imap] + + config.serialize_into_session(&:username) + config.serialize_from_session { |u| Usuaria.find(u) } + + config.failure_app = self + end + + set :root, File.expand_path(File.join(File.dirname(__FILE__), '..', '..')) + end +end diff --git a/lib/sutty/models/usuaria.rb b/lib/sutty/models/usuaria.rb new file mode 100644 index 00000000..92d79d3c --- /dev/null +++ b/lib/sutty/models/usuaria.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Sutty + # Una usuaria de Sutty + class Usuaria < OpenStruct + def self.find(username) + Usuaria.new(username: username) + end + end +end diff --git a/lib/warden/imap.rb b/lib/warden/imap.rb new file mode 100644 index 00000000..058c2c91 --- /dev/null +++ b/lib/warden/imap.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'net/imap' +require 'warden' +require 'email_address' + +# XXX Separación de concerns? +require_relative '../sutty/models/usuaria' + +module Warden + module IMAP + # Una estrategia de autenticación por IMAP + class Strategy < Warden::Strategies::Base + def valid? + return false unless params.include? 'username' + return false unless params.include? 'password' + + @email = EmailAddress.new(params['username']) + + return false unless @email.valid? + + true + end + + def authenticate! + imap_connect + imap_login + end + + private + + def imap_connect + # No vamos a enviar la contraseña en texto plano a ningún lado + @imap = Net::IMAP.new(@email.host_name, ssl: true) + # Errores más comunes según + # https://ruby-doc.org/stdlib-2.0.0/libdoc/net/imap/rdoc/Net/IMAP.html + rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::ENETUNREACH, + SocketError, Net::IMAP::ByeResponseError => e + + @imap.disconnect + fail! e.to_s + end + + def imap_login + @imap.login(@email.normal, params['password']) + @imap.disconnect + + success! Sutty::Usuaria.find(@email.normal) + rescue EOFError => e + @imap.disconnect + fail! e.to_s + end + end + end +end + +Warden::Strategies.add(:imap, Warden::IMAP::Strategy) diff --git a/sutty.rb b/sutty.rb new file mode 100644 index 00000000..eb9991e9 --- /dev/null +++ b/sutty.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require 'pry' unless ENV['RACK_ENV'] == 'production' +require_relative 'lib/sutty' diff --git a/views/500.haml b/views/500.haml new file mode 100644 index 00000000..563b1966 --- /dev/null +++ b/views/500.haml @@ -0,0 +1 @@ +%h1 Hubo un error 500! diff --git a/views/index.haml b/views/index.haml new file mode 100644 index 00000000..3d3f9f06 --- /dev/null +++ b/views/index.haml @@ -0,0 +1,3 @@ +%h1 + Hola + = current_user.username diff --git a/views/login.haml b/views/login.haml new file mode 100644 index 00000000..05db7fcb --- /dev/null +++ b/views/login.haml @@ -0,0 +1,11 @@ +%h1 Hola! + +- if flash[:error] + .alert.alert-danger{role: 'alert'} + = flash[:error] + +%form{method: 'post', action: '/login'} + %input{type: 'email', name: 'username', placeholder: 'Correo'} + %input{type: 'password', name: 'password', placeholder: 'Contraseña'} + + %input{type: 'submit', value: 'Ingresar'}