social_stream-oauth2_server 2.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +5 -0
  4. data/README.rdoc +3 -0
  5. data/Rakefile +26 -0
  6. data/app/assets/images/logos/small/site.png +0 -0
  7. data/app/assets/javascripts/social_stream-oauth2_server.js +6 -0
  8. data/app/assets/javascripts/social_stream/site_client.js +15 -0
  9. data/app/assets/stylesheets/social_stream-oauth2_server.css.sass +24 -0
  10. data/app/assets/stylesheets/social_stream/oauth2_server/applications/_applications-oauth2server.css.sass +45 -0
  11. data/app/assets/stylesheets/social_stream/oauth2_server/applications/layout/_applications-oauth2server.css.sass +51 -0
  12. data/app/assets/stylesheets/social_stream/oauth2_server/applications/responsive/_responsive-1200px-min.css.sass +7 -0
  13. data/app/assets/stylesheets/social_stream/oauth2_server/applications/responsive/_responsive-767px-max.css.sass +35 -0
  14. data/app/assets/stylesheets/social_stream/oauth2_server/applications/responsive/_responsive-768px-979px.css.sass +8 -0
  15. data/app/assets/stylesheets/social_stream/oauth2_server/create/_create-oauth2server.css.sass +11 -0
  16. data/app/assets/stylesheets/social_stream/oauth2_server/create/_error_create-oauth2server.css.sass +13 -0
  17. data/app/assets/stylesheets/social_stream/oauth2_server/create/layout/_create-oauth2server.css.sass +19 -0
  18. data/app/assets/stylesheets/social_stream/oauth2_server/create/responsive/_responsive-1200px-min.css.sass +7 -0
  19. data/app/assets/stylesheets/social_stream/oauth2_server/create/responsive/_responsive-767px-max.css.sass +16 -0
  20. data/app/assets/stylesheets/social_stream/oauth2_server/create/responsive/_responsive-768px-979px.css.sass +8 -0
  21. data/app/assets/stylesheets/social_stream/oauth2_server/show/_show-oauth2server.css.sass +42 -0
  22. data/app/assets/stylesheets/social_stream/oauth2_server/show/layout/_show-oauth2server.css.sass +71 -0
  23. data/app/assets/stylesheets/social_stream/oauth2_server/show/responsive/_responsive-1200px-min.css.sass +7 -0
  24. data/app/assets/stylesheets/social_stream/oauth2_server/show/responsive/_responsive-767px-max.css.sass +16 -0
  25. data/app/assets/stylesheets/social_stream/oauth2_server/show/responsive/_responsive-768px-979px.css.sass +8 -0
  26. data/app/controllers/authorizations_controller.rb +67 -0
  27. data/app/controllers/site/clients_controller.rb +39 -0
  28. data/app/decorators/social_stream/base/actor_decorator.rb +3 -0
  29. data/app/decorators/social_stream/base/user_decorator.rb +3 -0
  30. data/app/helpers/site_client_helper.rb +17 -0
  31. data/app/models/oauth2_token.rb +33 -0
  32. data/app/models/oauth2_token/access_token.rb +32 -0
  33. data/app/models/oauth2_token/authorization_code.rb +5 -0
  34. data/app/models/oauth2_token/refresh_token.rb +7 -0
  35. data/app/models/relation/admin.rb +9 -0
  36. data/app/models/relation/auth.rb +8 -0
  37. data/app/models/site/client.rb +38 -0
  38. data/app/overrides/frontpage/_presentation/client_site_presentation.html.erb.deface +8 -0
  39. data/app/overrides/layouts/_header_dropdown_menu/applications_entry.html.erb.deface +4 -0
  40. data/app/views/authorizations/error.html.erb +4 -0
  41. data/app/views/authorizations/new.html.erb +27 -0
  42. data/app/views/site/clients/_form.html.erb +39 -0
  43. data/app/views/site/clients/_new.modal.html.erb +9 -0
  44. data/app/views/site/clients/_presentation.html.erb +13 -0
  45. data/app/views/site/clients/index.html.erb +42 -0
  46. data/app/views/site/clients/new.html.erb +10 -0
  47. data/app/views/site/clients/show.html.erb +44 -0
  48. data/config/locales/en.yml +29 -0
  49. data/config/locales/es.yml +29 -0
  50. data/config/routes.rb +10 -0
  51. data/db/migrate/20130115102300_create_social_stream_oauth2_server.rb +25 -0
  52. data/lib/generators/social_stream/oauth2_server/install_generator.rb +23 -0
  53. data/lib/social_stream-oauth2_server.rb +19 -0
  54. data/lib/social_stream/migrations/oauth2_server.rb +8 -0
  55. data/lib/social_stream/oauth2_server.rb +5 -0
  56. data/lib/social_stream/oauth2_server/controllers/helpers.rb +41 -0
  57. data/lib/social_stream/oauth2_server/engine.rb +21 -0
  58. data/lib/social_stream/oauth2_server/models/actor.rb +11 -0
  59. data/lib/social_stream/oauth2_server/models/user.rb +35 -0
  60. data/lib/social_stream/oauth2_server/token_endpoint.rb +41 -0
  61. data/lib/social_stream/oauth2_server/version.rb +5 -0
  62. data/lib/tasks/db/populate.rake +37 -0
  63. data/social_stream-oauth2_server.gemspec +19 -0
  64. data/spec/controllers/authorizations_controller_spec.rb +179 -0
  65. data/spec/controllers/dummy_controller_spec.rb +43 -0
  66. data/spec/factories/site_client.rb +6 -0
  67. data/spec/models/relation/auth_spec.rb +15 -0
  68. data/spec/models/site/client_spec.rb +22 -0
  69. metadata +156 -0
@@ -0,0 +1,7 @@
1
+ //
2
+ // Responsive: Large desktop and up
3
+ // --------------------------------------------------
4
+
5
+
6
+ @media (min-width: 1200px)
7
+
@@ -0,0 +1,16 @@
1
+ //
2
+ // Responsive: Landscape phone to desktop/tablet
3
+ // --------------------------------------------------
4
+
5
+
6
+ @media (max-width: 767px)
7
+
8
+
9
+
10
+
11
+ // UP TO LANDSCAPE PHONE
12
+ // ---------------------
13
+
14
+ @media (max-width: 480px)
15
+
16
+
@@ -0,0 +1,8 @@
1
+ //
2
+ // Responsive: Tablet to desktop
3
+ // --------------------------------------------------
4
+
5
+
6
+ @media (min-width: 768px) and (max-width: 1119px)
7
+
8
+
@@ -0,0 +1,67 @@
1
+ class AuthorizationsController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
5
+ @error = e
6
+ render :error, :status => e.status
7
+ end
8
+
9
+ def new
10
+ respond *authorize_endpoint.call(request.env)
11
+ end
12
+
13
+ def create
14
+ respond *authorize_endpoint(:allow_approval).call(request.env)
15
+ end
16
+
17
+ private
18
+
19
+ def respond(status, header, response)
20
+ ["WWW-Authenticate"].each do |key|
21
+ headers[key] = header[key] if header[key].present?
22
+ end
23
+
24
+ if response.redirect?
25
+ redirect_to header['Location']
26
+ else
27
+ render :new
28
+ end
29
+ end
30
+
31
+ def authorize_endpoint(allow_approval = false)
32
+ Rack::OAuth2::Server::Authorize.new do |req, res|
33
+ @client = Site::Client.find(req.client_id) || req.bad_request!
34
+
35
+ res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.callback_url)
36
+
37
+ if allow_approval
38
+ if params[:accept]
39
+ current_user.client_authorize!(@client)
40
+
41
+ approve!(req, res, @client)
42
+ else
43
+ req.access_denied!
44
+ end
45
+ else
46
+ if current_user.client_authorized?(@client)
47
+ approve!(req, res, @client)
48
+ else
49
+ @response_type = req.response_type
50
+ @state = req.state
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def approve!(req, res, client)
57
+ case req.response_type
58
+ when :code
59
+ authorization_code = current_user.authorization_codes.create!(:client => client, :redirect_uri => res.redirect_uri)
60
+ res.code = authorization_code.token
61
+ when :token
62
+ res.access_token = current_user.access_tokens.create!(:client => client).to_bearer_token
63
+ end
64
+
65
+ res.approve!
66
+ end
67
+ end
@@ -0,0 +1,39 @@
1
+ class Site::ClientsController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ before_filter :set_author_ids, only: [ :create, :update ]
5
+
6
+ def index
7
+ @developer_clients = current_subject.developer_site_clients
8
+ end
9
+
10
+ def show
11
+ @client = Site::Client.find params[:id]
12
+ end
13
+
14
+ def new
15
+ @client = Site::Client.new
16
+ end
17
+
18
+ def create
19
+ @client = Site::Client.new params[:site_client]
20
+
21
+ if @client.save
22
+ respond_to do |format|
23
+ format.html { redirect_to @client }
24
+ end
25
+ else
26
+ respond_to do |format|
27
+ format.html { render :new }
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def set_author_ids
35
+ params[:site_client][:author_id] = current_subject.actor_id
36
+ params[:site_client][:user_author_id] = current_user.actor_id
37
+ params[:site_client][:owner_id] = current_subject.actor_id
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ Actor.class_eval do
2
+ include SocialStream::Oauth2Server::Models::Actor
3
+ end
@@ -0,0 +1,3 @@
1
+ User.class_eval do
2
+ include SocialStream::Oauth2Server::Models::User
3
+ end
@@ -0,0 +1,17 @@
1
+ module SiteClientHelper
2
+ # Extract {Site::Client} id form Devise's redirect_to
3
+ def redirect_to_site_client_id
4
+ uri = URI.parse session["user_return_to"]
5
+
6
+ Rack::Utils.parse_query(uri.query)["client_id"]
7
+ rescue
8
+ end
9
+
10
+ def redirect_to_site_client?
11
+ redirect_to_site_client_id.present?
12
+ end
13
+
14
+ def redirecting_site_client
15
+ Site::Client.find redirect_to_site_client_id
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ class Oauth2Token < ActiveRecord::Base
2
+ cattr_accessor :default_lifetime
3
+ self.default_lifetime = 1.minute
4
+
5
+ belongs_to :user
6
+ belongs_to :client,
7
+ class_name: "Site::Client",
8
+ foreign_key: :site_id
9
+
10
+ validates :client, :expires_at, presence: true
11
+ validates :token, presence: true, uniqueness: true
12
+
13
+ before_validation :setup, on: :create
14
+
15
+ scope :valid, lambda {
16
+ where('expires_at >= ?', Time.now.utc)
17
+ }
18
+
19
+ def expires_in
20
+ (expires_at - Time.now.utc).to_i
21
+ end
22
+
23
+ def expire!
24
+ update_attribute(:expires_at, Time.now.utc) || raise(ActiveRecord::RecordInvalid)
25
+ end
26
+
27
+ protected
28
+
29
+ def setup
30
+ self.token = SecureRandom.base64(64)
31
+ self.expires_at ||= default_lifetime.from_now
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ class Oauth2Token::AccessToken < Oauth2Token
2
+ self.default_lifetime = 15.minutes
3
+
4
+ belongs_to :refresh_token,
5
+ class_name: "Oauth2Token::RefreshToken"
6
+
7
+ def to_bearer_token(with_refresh_token = false)
8
+ bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
9
+ access_token: token,
10
+ expires_in: expires_in
11
+ )
12
+
13
+ if with_refresh_token
14
+ bearer_token.refresh_token = create_refresh_token!(
15
+ user: user,
16
+ client: client
17
+ ).token
18
+ end
19
+
20
+ bearer_token
21
+ end
22
+
23
+ def setup
24
+ super
25
+
26
+ if refresh_token
27
+ self.user = refresh_token.user
28
+ self.client = refresh_token.client
29
+ self.expires_at = [ expires_at, refresh_token.expires_at ].min
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ class Oauth2Token::AuthorizationCode < Oauth2Token
2
+ def access_token
3
+ @access_token ||= expire! && user.access_tokens.create!(client: client)
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ class Oauth2Token::RefreshToken < Oauth2Token
2
+ self.default_lifetime = 1.month
3
+
4
+ has_many :access_tokens,
5
+ class_name: 'Oauth2Token::AccessToken'
6
+
7
+ end
@@ -0,0 +1,9 @@
1
+ # Administer client sites
2
+ class Relation::Admin < Relation::Single
3
+ class << self
4
+ def create_activity?
5
+ false
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,8 @@
1
+ # Authorize a {Site::Client} to access data
2
+ class Relation::Auth < Relation::Single
3
+ class << self
4
+ def create_activity?
5
+ false
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ class Site::Client < Site
2
+ validates_presence_of :url, :callback_url, :secret
3
+
4
+ before_validation :set_secret,
5
+ on: :create
6
+
7
+ after_create :set_admin
8
+
9
+ scope :administered_by, lambda { |actor|
10
+ joins(actor: :sent_ties).
11
+ merge(Contact.received_by(actor)).
12
+ merge(Tie.related_by(Relation::Admin.instance))
13
+ }
14
+
15
+ %w{ url callback_url secret }.each do |m|
16
+ define_method m do
17
+ config[m]
18
+ end
19
+
20
+ define_method "#{ m }=" do |arg|
21
+ config[m] = arg
22
+ end
23
+ end
24
+
25
+ def to_param
26
+ id
27
+ end
28
+
29
+ private
30
+
31
+ def set_secret
32
+ self.secret = SecureRandom.hex(64)
33
+ end
34
+
35
+ def set_admin
36
+ contact_to!(author).relation_ids = [ Relation::Admin.instance.id ]
37
+ end
38
+ end
@@ -0,0 +1,8 @@
1
+ <!-- surround_contents '#presentation' -->
2
+
3
+ <% if redirect_to_site_client? %>
4
+ <%= render partial: 'site/clients/presentation',
5
+ locals: { client: redirecting_site_client } %>
6
+ <% else %>
7
+ <%= render_original %>
8
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <!-- insert_after "code[erb-loud]:contains('header_dropdown_menu_sessions')" -->
2
+ <li>
3
+ <%= link_to t('account.applications'), site_clients_path %>
4
+ </li>
@@ -0,0 +1,4 @@
1
+ <h2>Invalid Authorization Request</h2>
2
+
3
+ <h3><%= @error.error %></h3>
4
+ <p><%= @error.description %></p>
@@ -0,0 +1,27 @@
1
+ <article class="authorization">
2
+ <h2>
3
+ <%= t 'authorization.new.title', client: @client.name %>
4
+ </h2>
5
+
6
+ <%= raw t('authorization.new.permission.title', client: link_to(@client.name, @client.url)) %>
7
+
8
+ <ul>
9
+ <li>
10
+ &#8226&#32<%= t 'permission.public_info' %>
11
+ </li>
12
+ </ul>
13
+
14
+ <%= form_tag authorizations_path do %>
15
+ <%= hidden_field_tag :client_id, @client.id %>
16
+ <%= hidden_field_tag :response_type, @response_type %>
17
+ <%= hidden_field_tag :redirect_uri, @redirect_uri %>
18
+ <%= hidden_field_tag :state, @state %>
19
+
20
+ <%= button_tag class: "btn btn-danger", name: "cancel" do %>
21
+ <%= t 'authorization.form.cancel' %>
22
+ <% end %>
23
+ <%= button_tag class: "btn btn-success", name: "accept" do %>
24
+ <%= t 'authorization.form.accept' %>
25
+ <% end %>
26
+ <% end %>
27
+ </article>
@@ -0,0 +1,39 @@
1
+ <article>
2
+ <%= form_for(@client || Site::Client.new) do |f| %>
3
+
4
+ <% if f.object.errors.any? %>
5
+ <div id="error_explanation" class="alert alert-error">
6
+ <h2><%= pluralize(f.object.errors.count, "error") %> prohibited this client site from being saved:</h2>
7
+
8
+ <ul>
9
+ <% f.object.errors.full_messages.each do |msg| %>
10
+ <li><%= msg %></li>
11
+ <% end %>
12
+ </ul>
13
+
14
+ </div>
15
+ <% end %>
16
+ <article id="new_application">
17
+ <section class="name">
18
+ <%= f.label :name %>
19
+ <%= f.text_field :name %>
20
+ </section>
21
+
22
+ <section class="description">
23
+ <%= f.label :description %>
24
+ <%= f.text_area :description %>
25
+ </section>
26
+
27
+ <section class="url">
28
+ <%= f.label :url %>
29
+ <%= f.text_area :url %>
30
+ </section>
31
+
32
+ <section class="callback_url">
33
+ <%= f.label :callback_url %>
34
+ <%= f.text_area :callback_url %>
35
+ </section>
36
+ <%= f.submit :class => "btn pull-right" %>
37
+ </article>
38
+ <% end %>
39
+ </article>
@@ -0,0 +1,9 @@
1
+ <div id="new_site_client-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="new_site_client-modal-title" aria-hidden="true">
2
+ <div class="modal-header">
3
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
4
+ <h3 id="new_site_client-modal-title"><%= t 'site.client.new.title' %></h3>
5
+ </div>
6
+ <div class="modal-body">
7
+ <%= render partial: 'form' %>
8
+ </div>
9
+ </div>
@@ -0,0 +1,13 @@
1
+ <article class="media">
2
+ <%= link_to client.url, class: 'pull-left' do %>
3
+ <%= image_tag client.logo.url(:small), style: "width: 70px; height: 70px;" %>
4
+ <% end %>
5
+
6
+ <div class="media-body">
7
+ <h2 class="media-heading">
8
+ <%= client.name %>
9
+ </h2>
10
+
11
+ <%= client.description %>
12
+ </div>
13
+ </article>
@@ -0,0 +1,42 @@
1
+ <section id="site_clients" class="first-img">
2
+
3
+ <%= render partial: 'toolbar/home' %>
4
+
5
+ <section class="site_clients">
6
+ <header>
7
+ <h1>
8
+ <%= t 'site.client.added' %>
9
+ </h1>
10
+
11
+ <%= link_to t('site.client.new.link'), new_site_client_path, class: "btn new_site_client-modal-link", 'data-toggle' => 'modal' %>
12
+
13
+ <%= render partial: 'new.modal' %>
14
+
15
+ <hr class="soften">
16
+ </header>
17
+
18
+ <% @developer_clients.each do |client| %>
19
+
20
+ <%= image_tag client.logo.url(:small), style: "width: 40px; height: 40px;" %>
21
+
22
+ <div class="name">
23
+ <%= link_to client.name, client %>
24
+ </div>
25
+ <div class="url">
26
+ <%= link_to client.url, client.url, target: '_blank' %>
27
+ </div>
28
+ <div class="users">
29
+ <span>
30
+ 5
31
+ </span>
32
+ users
33
+ </div>
34
+ <hr class="soften">
35
+ <% end %>
36
+
37
+ <%= javascript_tag do %>
38
+ SocialStream.SiteClient.index();
39
+ <% end %>
40
+
41
+ </section>
42
+ </section>