Bringing HTTP Basic back to the fold, starting with Campfire and Basecamp.
This commit is contained in:
parent
91533b7f45
commit
240d691253
9
Rakefile
9
Rakefile
|
@ -4,7 +4,7 @@ require 'term/ansicolor'
|
|||
|
||||
include Term::ANSIColor
|
||||
|
||||
OMNIAUTH_GEMS = %w(oa-core oa-basic oa-oauth oa-openid)
|
||||
OMNIAUTH_GEMS = %w(omniauth oa-core oa-oauth oa-openid)
|
||||
|
||||
desc 'Run specs for all of the gems.'
|
||||
task :spec do
|
||||
|
@ -16,5 +16,12 @@ task :spec do
|
|||
end
|
||||
end
|
||||
|
||||
desc 'Push all gems to Gemcutter'
|
||||
task :gemcutter do
|
||||
OMNIAUTH_GEMS.each_with_index do |dir, i|
|
||||
Dir.chdir(dir) { system('rake gemcutter') }
|
||||
end
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
require 'omniauth/core'
|
||||
require 'omniauth/strategies/http_basic'
|
||||
require 'omniauth/strategies/http_basic'
|
||||
|
||||
require 'omniauth/strategies/campfire'
|
||||
require 'omniauth/strategies/basecamp'
|
|
@ -0,0 +1,53 @@
|
|||
module OmniAuth
|
||||
module Strategies
|
||||
class Basecamp < HttpBasic
|
||||
def initialize(app)
|
||||
require 'json'
|
||||
super(app, :basecamp, nil)
|
||||
end
|
||||
|
||||
def endpoint
|
||||
"http://#{request.params['user']}:#{request.params['password']}@#{request.params['subdomain']}.basecamphq.com/me.xml"
|
||||
end
|
||||
|
||||
def perform_authentication(endpoint)
|
||||
super(endpoint) rescue super(endpoint.sub('http','https'))
|
||||
end
|
||||
|
||||
def auth_hash
|
||||
doc = Nokogiri::XML.parse(@response.body)
|
||||
OmniAuth::Utils.deep_merge(super, {
|
||||
'uid' => doc.xpath('person/id').text,
|
||||
'user_info' => user_info(doc),
|
||||
'credentials' => {
|
||||
'token' => doc.xpath('person/token').text
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def user_info(doc)
|
||||
hash = {
|
||||
'nickname' => request.params['user'],
|
||||
'first_name' => doc.xpath('person/first-name').text,
|
||||
'last_name' => doc.xpath('person/last-name').text,
|
||||
'email' => doc.xpath('person/email-address').text,
|
||||
'image' => doc.xpath('person/avatar-url').text
|
||||
}
|
||||
|
||||
hash['name'] = [hash['first_name'], hash['last_name']].join(' ').strip
|
||||
|
||||
hash.delete('image') if hash['image'].include?('missing/avatar.png')
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def get_credentials
|
||||
OmniAuth::Form.build('Basecamp Authentication') do
|
||||
text_field 'Subdomain', 'subdomain'
|
||||
text_field 'Username', 'user'
|
||||
password_field 'Password', 'password'
|
||||
end.to_response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,45 @@
|
|||
module OmniAuth
|
||||
module Strategies
|
||||
class Campfire < HttpBasic
|
||||
def initialize(app)
|
||||
require 'json'
|
||||
super(app, :campfire, nil)
|
||||
end
|
||||
|
||||
def endpoint
|
||||
"http://#{request.params['user']}:#{request.params['password']}@#{request.params['subdomain']}.campfirenow.com/users/me.json"
|
||||
end
|
||||
|
||||
def perform_authentication(endpoint)
|
||||
super(endpoint) rescue super(endpoint.sub('http','https'))
|
||||
end
|
||||
|
||||
def auth_hash
|
||||
user_hash = JSON.parse(@response.body)['user']
|
||||
OmniAuth::Utils.deep_merge(super, {
|
||||
'uid' => user_hash['id'],
|
||||
'user_info' => user_info(user_hash),
|
||||
'credentials' => {
|
||||
'token' => user_hash['api_auth_token']
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def user_info(hash)
|
||||
{
|
||||
'nickname' => request.params['user'],
|
||||
'name' => hash['name'],
|
||||
'email' => hash['email_address']
|
||||
}
|
||||
end
|
||||
|
||||
def get_credentials
|
||||
OmniAuth::Form.build('Campfire Authentication') do
|
||||
text_field 'Subdomain', 'subdomain'
|
||||
text_field 'Username', 'user'
|
||||
password_field 'Password', 'password'
|
||||
end.to_response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,18 +14,41 @@ module OmniAuth
|
|||
attr_reader :endpoint, :request_headers
|
||||
|
||||
def request_phase
|
||||
@response = RestClient.get(endpoint, request_headers)
|
||||
if env['REQUEST_METHOD'] == 'GET'
|
||||
get_credentials
|
||||
else
|
||||
perform
|
||||
end
|
||||
end
|
||||
|
||||
def title
|
||||
name.split('_').map{|s| s.capitalize}.join(' ')
|
||||
end
|
||||
|
||||
def get_credentials
|
||||
OmniAuth::Form.build(title) do
|
||||
text_field 'Username', 'username'
|
||||
password_field 'Password', 'password'
|
||||
end.to_response
|
||||
end
|
||||
|
||||
def perform
|
||||
@response = perform_authentication(endpoint)
|
||||
request.POST['auth'] = auth_hash
|
||||
@env['REQUEST_METHOD'] = 'GET'
|
||||
@env['PATH_INFO'] = "#{OmniAuth.config.path_prefix}/#{name}/callback"
|
||||
|
||||
|
||||
@app.call(@env)
|
||||
rescue RestClient::Request::Unauthorized
|
||||
fail!(:invalid_credentials)
|
||||
end
|
||||
|
||||
def perform_authentication(uri, headers = request_headers)
|
||||
RestClient.get(uri, headers)
|
||||
end
|
||||
|
||||
def callback_phase
|
||||
@app.call(env)
|
||||
fail!(:invalid_credentials)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
require 'rack'
|
||||
require 'singleton'
|
||||
|
||||
require 'omniauth/form'
|
||||
|
||||
module OmniAuth
|
||||
class Configuration
|
||||
include Singleton
|
||||
|
||||
def initialize
|
||||
@path_prefix = '/auth'
|
||||
@on_failure = Proc.new do |env, message_key|
|
||||
@@defaults = {
|
||||
:path_prefix => '/auth',
|
||||
:on_failure => Proc.new do |env, message_key|
|
||||
new_path = "#{OmniAuth.config.path_prefix}/failure?message=#{message_key}"
|
||||
[302, {'Location' => "#{new_path}"}, []]
|
||||
end
|
||||
end,
|
||||
:form_css => Form::DEFAULT_CSS
|
||||
}
|
||||
|
||||
def self.defaults
|
||||
@@defaults
|
||||
end
|
||||
|
||||
def initialize
|
||||
@@defaults.each_pair{|k,v| self.send("#{k}=",v)}
|
||||
end
|
||||
|
||||
def on_failure(&block)
|
||||
|
@ -21,7 +32,8 @@ module OmniAuth
|
|||
end
|
||||
end
|
||||
|
||||
attr_accessor :path_prefix
|
||||
attr_writer :on_failure
|
||||
attr_accessor :path_prefix, :form_css
|
||||
end
|
||||
|
||||
def self.config
|
||||
|
@ -33,7 +45,19 @@ module OmniAuth
|
|||
end
|
||||
|
||||
module Utils
|
||||
extend self
|
||||
CAMELIZE_SPECIAL = {
|
||||
'oauth' => 'OAuth',
|
||||
'oauth2' => 'OAuth2',
|
||||
'openid' => 'OpenID',
|
||||
'open_id' => 'OpenID',
|
||||
'github' => 'GitHub'
|
||||
}
|
||||
|
||||
module_function
|
||||
|
||||
def form_css
|
||||
"<style type='text/css'>#{OmniAuth.config.form_css}</style>"
|
||||
end
|
||||
|
||||
def deep_merge(hash, other_hash)
|
||||
target = hash.dup
|
||||
|
@ -50,14 +74,6 @@ module OmniAuth
|
|||
target
|
||||
end
|
||||
|
||||
CAMELIZE_SPECIAL = {
|
||||
'oauth' => 'OAuth',
|
||||
'oauth2' => 'OAuth2',
|
||||
'openid' => 'OpenID',
|
||||
'open_id' => 'OpenID',
|
||||
'github' => 'GitHub'
|
||||
}
|
||||
|
||||
def camelize(word, first_letter_in_uppercase = true)
|
||||
return CAMELIZE_SPECIAL[word.to_s] if CAMELIZE_SPECIAL[word.to_s]
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
module OmniAuth
|
||||
class Form
|
||||
DEFAULT_CSS = <<-CSS
|
||||
body {
|
||||
background: #ccc;
|
||||
font-family: "Lucida Grande", "Lucida Sans", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 30px auto 0px;
|
||||
font-size: 18px;
|
||||
padding: 10px 10px 15px;
|
||||
background: #555;
|
||||
color: white;
|
||||
width: 320px;
|
||||
border: 10px solid #444;
|
||||
border-bottom: 0;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
-webkit-border-top-left-radius: 10px;
|
||||
-webkit-border-top-right-radius: 10px;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
|
||||
h1, form {
|
||||
-moz-box-shadow: 2px 2px 7px rgba(0,0,0,0.3);
|
||||
-webkit-box-shadow: 2px 2px 7px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
form {
|
||||
background: white;
|
||||
border: 10px solid #eee;
|
||||
border-top: 0;
|
||||
padding: 20px;
|
||||
margin: 0px auto 40px;
|
||||
width: 300px;
|
||||
-moz-border-radius-bottomleft: 10px;
|
||||
-moz-border-radius-bottomright: 10px;
|
||||
-webkit-border-bottom-left-radius: 10px;
|
||||
-webkit-border-bottom-right-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 18px;
|
||||
padding: 4px 8px;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 22px;
|
||||
padding: 4px 8px;
|
||||
display: block;
|
||||
margin: 20px auto 0;
|
||||
}
|
||||
CSS
|
||||
|
||||
def initialize(title=nil)
|
||||
title ||= "Authentication Info Required"
|
||||
@html = ""
|
||||
header(title)
|
||||
end
|
||||
|
||||
def self.build(title=nil, &block)
|
||||
form = OmniAuth::Form.new(title)
|
||||
form.instance_eval(&block)
|
||||
end
|
||||
|
||||
def label_field(text, target)
|
||||
@html << "\n<label for='#{target}'>#{text}:</label>"
|
||||
self
|
||||
end
|
||||
|
||||
def input_field(type, name)
|
||||
@html << "\n<input type='#{type}' id='#{name}' name='#{name}'/>"
|
||||
self
|
||||
end
|
||||
|
||||
def text_field(label, name)
|
||||
label_field(label, name)
|
||||
input_field('text', name)
|
||||
self
|
||||
end
|
||||
|
||||
def password_field(label, name)
|
||||
label_field(label, name)
|
||||
input_field('password', name)
|
||||
self
|
||||
end
|
||||
|
||||
def header(title)
|
||||
@html << <<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>#{title}</title>
|
||||
#{css}
|
||||
</head>
|
||||
<body>
|
||||
<h1>#{title}</h1>
|
||||
<form method='post'>
|
||||
HTML
|
||||
self
|
||||
end
|
||||
|
||||
def footer
|
||||
return self if @footer
|
||||
@html << <<-HTML
|
||||
<button type='submit'>Connect</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
@footer = true
|
||||
self
|
||||
end
|
||||
|
||||
def to_html
|
||||
footer
|
||||
@html
|
||||
end
|
||||
|
||||
def to_response
|
||||
footer
|
||||
Rack::Response.new(@html).finish
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def css
|
||||
"\n<style type='text/css'>#{OmniAuth.config.form_css}</style>"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -45,7 +45,10 @@ module OmniAuth
|
|||
end
|
||||
|
||||
def request_phase
|
||||
return fail!(:missing_information) unless identifier
|
||||
identifier ? start : get_identifier
|
||||
end
|
||||
|
||||
def start
|
||||
openid = Rack::OpenID.new(dummy_app, @store)
|
||||
response = openid.call(env)
|
||||
case env['rack.openid.response']
|
||||
|
@ -56,11 +59,23 @@ module OmniAuth
|
|||
end
|
||||
end
|
||||
|
||||
def get_identifier
|
||||
response = app.call(env)
|
||||
if response[0] < 400
|
||||
response
|
||||
else
|
||||
OmniAuth::Form.build('OpenID Authentication') do
|
||||
text_field('OpenID Identifier', 'identifier')
|
||||
end.to_response
|
||||
end
|
||||
end
|
||||
|
||||
def callback_phase
|
||||
env['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
openid = Rack::OpenID.new(lambda{|env| [200,{},[]]}, @store)
|
||||
openid.call(env)
|
||||
resp = env.delete('rack.openid.response')
|
||||
|
||||
case resp.status
|
||||
when :failure
|
||||
fail!(:invalid_credentials)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.0.1
|
Loading…
Reference in New Issue