openstax_accounts 0.1.0
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.
- data/MIT-LICENSE +20 -0
- data/README.md +123 -0
- data/Rakefile +22 -0
- data/app/assets/javascripts/openstax/accounts/application.js +15 -0
- data/app/assets/stylesheets/openstax/accounts/application.css +13 -0
- data/app/assets/stylesheets/openstax/accounts/dev.css.scss +31 -0
- data/app/controllers/openstax/accounts/application_controller.rb +24 -0
- data/app/controllers/openstax/accounts/dev/dev_controller.rb +13 -0
- data/app/controllers/openstax/accounts/dev/users_controller.rb +21 -0
- data/app/controllers/openstax/accounts/sessions_controller.rb +41 -0
- data/app/handlers/openstax/accounts/dev/users_search.rb +38 -0
- data/app/handlers/openstax/accounts/sessions_omniauth_authenticated.rb +47 -0
- data/app/helpers/openstax/accounts/application_helper.rb +20 -0
- data/app/models/openstax/accounts/user.rb +42 -0
- data/app/routines/openstax/accounts/dev/create_user.rb +37 -0
- data/app/routines/openstax/accounts/search_users.rb +47 -0
- data/app/views/layouts/openstax/accounts/application.html.erb +14 -0
- data/app/views/openstax/accounts/dev/users/login.html.erb +17 -0
- data/app/views/openstax/accounts/dev/users/search.js.erb +21 -0
- data/app/views/openstax/accounts/shared/_attention.html.erb +3 -0
- data/app/views/openstax/accounts/users/_action_create_form.html.erb +9 -0
- data/app/views/openstax/accounts/users/_action_dialog.html.erb +10 -0
- data/app/views/openstax/accounts/users/_action_list.html.erb +33 -0
- data/app/views/openstax/accounts/users/_action_search.html.erb +25 -0
- data/app/views/openstax/accounts/users/action_search.js.erb +8 -0
- data/config/initializers/extend_builtins.rb +42 -0
- data/config/routes.rb +25 -0
- data/db/migrate/0_create_openstax_accounts_users.rb +18 -0
- data/lib/omniauth/strategies/openstax.rb +39 -0
- data/lib/openstax/accounts/action_list.rb +42 -0
- data/lib/openstax/accounts/current_user_manager.rb +103 -0
- data/lib/openstax/accounts/engine.rb +35 -0
- data/lib/openstax/accounts/route_helper.rb +34 -0
- data/lib/openstax/accounts/user_provider.rb +15 -0
- data/lib/openstax/accounts/version.rb +5 -0
- data/lib/openstax_accounts.rb +130 -0
- data/spec/controllers/openstax/accounts/dev/users_controller_spec.rb +20 -0
- data/spec/controllers/openstax/accounts/sessions_controller_spec.rb +29 -0
- data/spec/dummy/README.md +1 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/api/application_users_controller.rb +7 -0
- data/spec/dummy/app/controllers/api/dummy_controller.rb +11 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/config/application.rb +53 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +35 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/openstax_accounts.rb +11 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/openstax_accounts_user.rb +6 -0
- data/spec/lib/openstax_accounts_spec.rb +24 -0
- data/spec/models/openstax/accounts/user_spec.rb +13 -0
- data/spec/spec_helper.rb +41 -0
- metadata +401 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
<%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
|
2
|
+
License version 3 or later. See the COPYRIGHT file for details. %>
|
3
|
+
|
4
|
+
<%
|
5
|
+
users ||= []
|
6
|
+
%>
|
7
|
+
|
8
|
+
<% if list.num_columns > 0 %>
|
9
|
+
<table class="list" width="100%">
|
10
|
+
<% if list.has_headings? %>
|
11
|
+
<tr>
|
12
|
+
<% for ii in 0..list.num_columns - 1 %>
|
13
|
+
<th><%= list.get_heading(ii) %></th>
|
14
|
+
<% end %>
|
15
|
+
</tr>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<% if users.empty? %>
|
19
|
+
<tr>
|
20
|
+
<td colspan="<%= list.num_columns %>">No results</td>
|
21
|
+
</tr>
|
22
|
+
<% else %>
|
23
|
+
<% users.all.each_with_index do |user, uu| %>
|
24
|
+
<tr>
|
25
|
+
<% for cc in 0..list.num_columns - 1 %>
|
26
|
+
<% width = uu == 0 ? list.get_width(cc) : nil %>
|
27
|
+
<td <%= "width=#{width}" if width %>><%= list.get_data(cc, user) %></td>
|
28
|
+
<% end %>
|
29
|
+
</tr>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
32
|
+
</table>
|
33
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
|
2
|
+
License version 3 or later. See the COPYRIGHT file for details. %>
|
3
|
+
|
4
|
+
<%
|
5
|
+
# Clients of this partial must supply the following variables:
|
6
|
+
# action_search_path
|
7
|
+
%>
|
8
|
+
|
9
|
+
<div id="action-search-errors"></div>
|
10
|
+
|
11
|
+
<%= lev_form_for :search,
|
12
|
+
url: action_search_path,
|
13
|
+
html: {id: 'action-search-form'},
|
14
|
+
remote: true do |f| %>
|
15
|
+
|
16
|
+
Search for
|
17
|
+
<%= f.text_field :search_terms, style: 'width:300px' %>
|
18
|
+
in
|
19
|
+
<%= f.select :search_type, options_for_select(['Any', 'Name', 'Username']) %>
|
20
|
+
|
21
|
+
<%= submit_tag 'Search' %>
|
22
|
+
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<div id="action-search-results-list"></div>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ActionController::Base
|
2
|
+
|
3
|
+
# Returns the current app user
|
4
|
+
def current_user
|
5
|
+
current_user_manager.current_user
|
6
|
+
end
|
7
|
+
|
8
|
+
# Signs in the given user; the argument can be either an accounts user or
|
9
|
+
# an app user
|
10
|
+
def sign_in(user)
|
11
|
+
current_user_manager.sign_in(user)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Signs out the current user
|
15
|
+
def sign_out!
|
16
|
+
current_user_manager.sign_out!
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns true iff there is a user signed in
|
20
|
+
def signed_in?
|
21
|
+
current_user_manager.signed_in?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Useful in before_filters
|
25
|
+
def authenticate_user!
|
26
|
+
return if signed_in?
|
27
|
+
session[:return_to] = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
|
28
|
+
redirect_to openstax_accounts.login_path
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
helper_method :current_user, :signed_in?
|
34
|
+
|
35
|
+
def current_user_manager
|
36
|
+
@current_user_manager ||= OpenStax::Accounts::CurrentUserManager.new(request,
|
37
|
+
session,
|
38
|
+
cookies)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
data/config/routes.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
OpenStax::Accounts::Engine.routes.draw do
|
2
|
+
match '/auth/openstax/callback', to: 'sessions#omniauth_authenticated' #omniauth route
|
3
|
+
get '/auth/openstax', :as => 'openstax_login'
|
4
|
+
|
5
|
+
get 'sessions/new', :as => 'login'
|
6
|
+
# See https://github.com/plataformatec/devise/commit/f3385e96abf50e80d2ae282e1fb9bdad87a83d3c
|
7
|
+
match 'sessions/destroy', :as => 'logout',
|
8
|
+
:via => OpenStax::Accounts.configuration.logout_via
|
9
|
+
|
10
|
+
if OpenStax::Accounts.configuration.enable_stubbing?
|
11
|
+
namespace :dev do
|
12
|
+
resources :users, :only => [] do
|
13
|
+
collection do
|
14
|
+
get 'login'
|
15
|
+
post 'search'
|
16
|
+
post 'become'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
hh = OpenStax::Accounts::Engine.routes.url_helpers
|
24
|
+
|
25
|
+
OpenStax::Accounts::RouteHelper.register_path(:login, hh.openstax_login_path) { hh.login_dev_users_path }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateOpenStaxAccountsUsers < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :openstax_accounts_users do |t|
|
4
|
+
t.integer :openstax_uid
|
5
|
+
t.string :username
|
6
|
+
t.string :first_name
|
7
|
+
t.string :last_name
|
8
|
+
t.string :full_name
|
9
|
+
t.string :title
|
10
|
+
t.string :access_token
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :openstax_accounts_users, :openstax_uid, :unique => true
|
16
|
+
add_index :openstax_accounts_users, :username, :unique => true
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
require 'omniauth-oauth2'
|
3
|
+
|
4
|
+
module OmniAuth
|
5
|
+
module Strategies
|
6
|
+
class Openstax < OAuth2
|
7
|
+
option :name, "openstax"
|
8
|
+
|
9
|
+
option :client_options, {
|
10
|
+
:site => "http://accounts.openstax.org",
|
11
|
+
:authorize_url => "/oauth/authorize"
|
12
|
+
}
|
13
|
+
|
14
|
+
uid { raw_info["id"] }
|
15
|
+
|
16
|
+
info do
|
17
|
+
username = raw_info["username"]
|
18
|
+
title = raw_info["title"]
|
19
|
+
first_name = raw_info["first_name"]
|
20
|
+
last_name = raw_info["last_name"]
|
21
|
+
full_name = raw_info["full_name"] || "#{first_name} #{last_name}"
|
22
|
+
full_name = username if full_name.blank?
|
23
|
+
|
24
|
+
# Changed to conform to the omniauth schema
|
25
|
+
{
|
26
|
+
name: full_name,
|
27
|
+
nickname: username,
|
28
|
+
first_name: first_name,
|
29
|
+
last_name: last_name,
|
30
|
+
title: title
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def raw_info
|
35
|
+
@raw_info ||= access_token.get('/api/users/me.json').parsed
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
class ActionList
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@options = options
|
7
|
+
|
8
|
+
raise IllegalArgument, "must supply data procs" if options[:data_procs].nil?
|
9
|
+
|
10
|
+
if options[:headings].present? && options[:data_procs].size != options[:headings].size
|
11
|
+
raise IllegalArgument, "if you supply headings, you must supply one for each column"
|
12
|
+
end
|
13
|
+
|
14
|
+
if options[:widths].present? && options[:data_procs].size != options[:widths].size
|
15
|
+
raise IllegalArgument, "if you supply widths, you must supply one for each column"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def num_columns
|
21
|
+
@options[:data_procs].size
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_headings?
|
25
|
+
@options[:headings].present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_heading(column)
|
29
|
+
@options[:headings].nil? ? nil : @options[:headings][column]
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_width(column)
|
33
|
+
@options[:widths].nil? ? nil : @options[:widths][column]
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_data(column, *args)
|
37
|
+
@options[:data_procs][column].call(*args)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
class CurrentUserManager
|
4
|
+
|
5
|
+
# References:
|
6
|
+
# http://railscasts.com/episodes/356-dangers-of-session-hijacking
|
7
|
+
|
8
|
+
def initialize(request, session, cookies)
|
9
|
+
@request = request
|
10
|
+
@session = session
|
11
|
+
@cookies = cookies
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the current app user
|
15
|
+
def current_user
|
16
|
+
load_current_users
|
17
|
+
@app_current_user
|
18
|
+
end
|
19
|
+
|
20
|
+
# Signs in the given user; the argument can be either an accounts user or
|
21
|
+
# an app user
|
22
|
+
def sign_in(user)
|
23
|
+
user.is_a?(User) ?
|
24
|
+
self.accounts_current_user = user :
|
25
|
+
self.current_user = user
|
26
|
+
end
|
27
|
+
|
28
|
+
# Signs out the user
|
29
|
+
def sign_out!
|
30
|
+
sign_in(OpenStax::Accounts::User.anonymous)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true iff there is a user signed in
|
34
|
+
def signed_in?
|
35
|
+
!accounts_current_user.is_anonymous?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the current accounts user
|
39
|
+
def accounts_current_user
|
40
|
+
load_current_users
|
41
|
+
@accounts_current_user
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# If they are nil (unset), sets the current users based on the session state
|
47
|
+
def load_current_users
|
48
|
+
return if !@accounts_current_user.nil?
|
49
|
+
|
50
|
+
if @request.ssl? && @cookies.signed[:secure_user_id] != "secure#{@session[:user_id]}"
|
51
|
+
sign_out! # hijacked
|
52
|
+
else
|
53
|
+
# If there is a session user_id, load up that user, otherwise set the anonymous user.
|
54
|
+
|
55
|
+
if @session[:user_id]
|
56
|
+
@accounts_current_user = User.where(id: @session[:user_id]).first
|
57
|
+
|
58
|
+
# It could happen (normally in development) that there is a session
|
59
|
+
# user_id that doesn't map to a User in the db.
|
60
|
+
# In such a case, sign_out! to reset the state
|
61
|
+
if @accounts_current_user.nil?
|
62
|
+
sign_out!
|
63
|
+
return
|
64
|
+
end
|
65
|
+
else
|
66
|
+
@accounts_current_user = User.anonymous
|
67
|
+
end
|
68
|
+
|
69
|
+
# Bring the app user inline with the accounts user
|
70
|
+
@app_current_user = user_provider.accounts_user_to_app_user(@accounts_current_user)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sets (signs in) the provided app user.
|
75
|
+
def current_user=(user)
|
76
|
+
self.accounts_current_user = user_provider.app_user_to_accounts_user(user)
|
77
|
+
@app_current_user
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sets the current accounts user, updates the app user, and also updates
|
81
|
+
# the session and cookie state.
|
82
|
+
def accounts_current_user=(user)
|
83
|
+
@accounts_current_user = user || User.anonymous
|
84
|
+
@app_current_user = user_provider.accounts_user_to_app_user(@accounts_current_user)
|
85
|
+
|
86
|
+
if @accounts_current_user.is_anonymous?
|
87
|
+
@session[:user_id] = nil
|
88
|
+
@cookies.delete(:secure_user_id)
|
89
|
+
else
|
90
|
+
@session[:user_id] = @accounts_current_user.id
|
91
|
+
@cookies.signed[:secure_user_id] = {secure: true, value: "secure#{@accounts_current_user.id}"}
|
92
|
+
end
|
93
|
+
|
94
|
+
@accounts_current_user
|
95
|
+
end
|
96
|
+
|
97
|
+
def user_provider
|
98
|
+
OpenStax::Accounts.configuration.user_provider
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
require 'omniauth/strategies/openstax'
|
3
|
+
require 'lev'
|
4
|
+
|
5
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
6
|
+
inflect.acronym 'OpenStax'
|
7
|
+
end
|
8
|
+
|
9
|
+
module OpenStax
|
10
|
+
module Accounts
|
11
|
+
class Engine < ::Rails::Engine
|
12
|
+
isolate_namespace OpenStax::Accounts
|
13
|
+
|
14
|
+
config.generators do |g|
|
15
|
+
g.test_framework :rspec, :view_specs => false, :fixture => false
|
16
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
17
|
+
g.assets false
|
18
|
+
g.helper false
|
19
|
+
end
|
20
|
+
|
21
|
+
SETUP_PROC = lambda do |env|
|
22
|
+
env['omniauth.strategy'].options[:client_options][:site] = OpenStax::Accounts.configuration.openstax_accounts_url
|
23
|
+
end
|
24
|
+
|
25
|
+
# Doesn't work to put this omniauth code in an engine initializer, instead:
|
26
|
+
# https://gist.github.com/pablomarti/5243118
|
27
|
+
middleware.use ::OmniAuth::Builder do
|
28
|
+
provider :openstax,
|
29
|
+
OpenStax::Accounts.configuration.openstax_application_id,
|
30
|
+
OpenStax::Accounts.configuration.openstax_application_secret,
|
31
|
+
:setup => SETUP_PROC
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Accounts
|
5
|
+
class RouteHelper
|
6
|
+
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# Registers a path against a canonical name. An optional
|
10
|
+
# block can be provided to give the stubbed path
|
11
|
+
def self.register_path(canonical_name, path, &block)
|
12
|
+
instance.paths[canonical_name] = path
|
13
|
+
if block.present? && OpenStax::Accounts.configuration.enable_stubbing?
|
14
|
+
instance.stubbed_paths[canonical_name] = block.call
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get_path(canonical_name)
|
19
|
+
OpenStax::Accounts.configuration.enable_stubbing? ?
|
20
|
+
instance.stubbed_paths[canonical_name] :
|
21
|
+
instance.paths[canonical_name]
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
self.paths = {}
|
26
|
+
self.stubbed_paths = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :paths
|
30
|
+
attr_accessor :stubbed_paths
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'openstax/accounts/version'
|
2
|
+
require 'openstax/accounts/engine'
|
3
|
+
require 'openstax/accounts/route_helper'
|
4
|
+
require 'openstax/accounts/action_list'
|
5
|
+
require 'openstax/accounts/user_provider'
|
6
|
+
require 'openstax/accounts/current_user_manager'
|
7
|
+
|
8
|
+
require 'openstax_utilities'
|
9
|
+
require 'uri'
|
10
|
+
require 'oauth2'
|
11
|
+
|
12
|
+
module OpenStax
|
13
|
+
module Accounts
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
###########################################################################
|
18
|
+
#
|
19
|
+
# Configuration machinery.
|
20
|
+
#
|
21
|
+
# To configure OpenStax Accounts, put the following code in your
|
22
|
+
# application's initialization logic
|
23
|
+
# (eg. in the config/initializers in a Rails app)
|
24
|
+
#
|
25
|
+
# OpenStax::Accounts.configure do |config|
|
26
|
+
# config.<parameter name> = <parameter value>
|
27
|
+
# ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Set enable_stubbing to true iff you want this engine to fake all
|
31
|
+
# interaction with the accounts site.
|
32
|
+
#
|
33
|
+
|
34
|
+
def configure
|
35
|
+
yield configuration
|
36
|
+
end
|
37
|
+
|
38
|
+
def configuration
|
39
|
+
@configuration ||= Configuration.new
|
40
|
+
end
|
41
|
+
|
42
|
+
class Configuration
|
43
|
+
attr_accessor :openstax_application_id
|
44
|
+
attr_accessor :openstax_application_secret
|
45
|
+
attr_accessor :enable_stubbing
|
46
|
+
attr_reader :openstax_accounts_url
|
47
|
+
attr_accessor :logout_via
|
48
|
+
attr_accessor :default_errors_partial
|
49
|
+
attr_accessor :default_errors_html_id
|
50
|
+
attr_accessor :default_errors_added_trigger
|
51
|
+
attr_accessor :security_transgression_exception
|
52
|
+
|
53
|
+
# See the "user_provider" discussion in the README
|
54
|
+
attr_accessor :user_provider
|
55
|
+
|
56
|
+
def openstax_accounts_url=(url)
|
57
|
+
url.gsub!(/https|http/,'https') if !(url =~ /localhost/)
|
58
|
+
url = url + "/" if url[url.size-1] != '/'
|
59
|
+
@openstax_accounts_url = url
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@openstax_application_id = 'SET ME!'
|
64
|
+
@openstax_application_secret = 'SET ME!'
|
65
|
+
@openstax_accounts_url = 'https://accounts.openstax.org/'
|
66
|
+
@enable_stubbing = true
|
67
|
+
@logout_via = :get
|
68
|
+
@default_errors_partial = 'openstax/accounts/shared/attention'
|
69
|
+
@default_errors_html_id = 'openstax-accounts-attention'
|
70
|
+
@default_errors_added_trigger = 'openstax-accounts-errors-added'
|
71
|
+
@security_transgression_exception = SecurityTransgression
|
72
|
+
@user_provider = OpenStax::Accounts::UserProvider
|
73
|
+
super
|
74
|
+
end
|
75
|
+
|
76
|
+
def enable_stubbing?
|
77
|
+
!Rails.env.production? && enable_stubbing
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Executes an OpenStax Accounts API call, using the given HTTP method,
|
82
|
+
# API url and request options.
|
83
|
+
# Any options accepted by OAuth2 requests can be used, such as
|
84
|
+
# :params, :body, :headers, etc, plus the :access_token option, which can
|
85
|
+
# be used to manually specify an OAuth access token.
|
86
|
+
# On failure, it can throw Faraday::ConnectionFailed for connection errors
|
87
|
+
# or OAuth2::Error if Accounts returns an HTTP 400 error,
|
88
|
+
# such as 422 Unprocessable Entity.
|
89
|
+
# On success, returns an OAuth2::Response object.
|
90
|
+
def api_call(http_method, url, options = {})
|
91
|
+
version = options.delete(:api_version)
|
92
|
+
unless version.blank?
|
93
|
+
options[:headers] ||= {}
|
94
|
+
options[:headers].merge!({ 'Accept' => "application/vnd.accounts.openstax.#{version.to_s}" })
|
95
|
+
end
|
96
|
+
|
97
|
+
token_string = options.delete(:access_token)
|
98
|
+
token = token_string.blank? ? client.client_credentials.get_token :
|
99
|
+
OAuth2::AccessToken.new(client, token_string)
|
100
|
+
|
101
|
+
api_url = URI.join(configuration.openstax_accounts_url, 'api/', url)
|
102
|
+
|
103
|
+
token.request(http_method, api_url, options)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Creates an ApplicationUser in Accounts for this app and the given
|
107
|
+
# OpenStax::Accounts::User.
|
108
|
+
# Also takes an optional API version parameter. Defaults to :v1.
|
109
|
+
# On failure, throws an Exception, just like api_call.
|
110
|
+
# On success, returns an OAuth2::Response object.
|
111
|
+
def create_application_user(user, version = nil)
|
112
|
+
options = {:access_token => user.access_token,
|
113
|
+
:api_version => (version.nil? ? :v1 : version)}
|
114
|
+
api_call(:post, 'application_users', options)
|
115
|
+
end
|
116
|
+
|
117
|
+
protected
|
118
|
+
|
119
|
+
def client
|
120
|
+
@client ||= OAuth2::Client.new(
|
121
|
+
configuration.openstax_application_id,
|
122
|
+
configuration.openstax_application_secret,
|
123
|
+
:site => configuration.openstax_accounts_url
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module OpenStax::Accounts
|
4
|
+
module Dev
|
5
|
+
describe UsersController do
|
6
|
+
routes { OpenStax::Accounts::Engine.routes }
|
7
|
+
|
8
|
+
let!(:user) { OpenStax::Accounts::User.create(username: 'some_user',
|
9
|
+
openstax_uid: 1) }
|
10
|
+
|
11
|
+
it 'should allow users not in production to become other users' do
|
12
|
+
expect(controller.current_user).to eq(OpenStax::Accounts::User.anonymous)
|
13
|
+
expect(controller.current_user.is_anonymous?).to eq(true)
|
14
|
+
get :become, user_id: user.id
|
15
|
+
expect(controller.current_user).to eq(user)
|
16
|
+
expect(controller.current_user.is_anonymous?).to eq(false)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module OpenStax::Accounts
|
4
|
+
describe SessionsController do
|
5
|
+
routes { OpenStax::Accounts::Engine.routes }
|
6
|
+
|
7
|
+
let!(:user) { OpenStax::Accounts::User.create(username: 'some_user',
|
8
|
+
openstax_uid: 1) }
|
9
|
+
|
10
|
+
it 'should redirect users to the login path' do
|
11
|
+
get :new
|
12
|
+
expect(response).to redirect_to RouteHelper.get_path(:login)
|
13
|
+
expect(response.code).to eq('302')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should authenticate users based on the oauth callback' do
|
17
|
+
# TODO
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should let users logout' do
|
21
|
+
controller.sign_in user
|
22
|
+
expect(controller.current_user).to eq(user)
|
23
|
+
expect(controller.current_user.is_anonymous?).to eq(false)
|
24
|
+
delete :destroy
|
25
|
+
expect(controller.current_user).to eq(OpenStax::Accounts::User.anonymous)
|
26
|
+
expect(controller.current_user.is_anonymous?).to eq(true)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dummy application used to test the OpenStax Accounts engine.
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Api
|
2
|
+
class DummyController < ApplicationController
|
3
|
+
class << self; attr_accessor :last_action, :last_params end
|
4
|
+
|
5
|
+
def dummy(action_name = :dummy)
|
6
|
+
self.class.last_action = action_name
|
7
|
+
self.class.last_params = params
|
8
|
+
render :json => { :head => :no_content }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|