maestrano-rails 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.
Files changed (96) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +164 -0
  3. data/Rakefile +38 -0
  4. data/app/controllers/maestrano/rails/saml_base_controller.rb +39 -0
  5. data/lib/generators/active_record/maestrano_group_generator.rb +38 -0
  6. data/lib/generators/active_record/maestrano_user_generator.rb +38 -0
  7. data/lib/generators/active_record/templates/migration.rb +12 -0
  8. data/lib/generators/maestrano/USAGE +2 -0
  9. data/lib/generators/maestrano/group_generator.rb +11 -0
  10. data/lib/generators/maestrano/install_generator.rb +30 -0
  11. data/lib/generators/maestrano/orm_helpers.rb +75 -0
  12. data/lib/generators/maestrano/templates/maestrano.rb +84 -0
  13. data/lib/generators/maestrano/templates/saml_controller.rb +52 -0
  14. data/lib/generators/maestrano/user_generator.rb +11 -0
  15. data/lib/generators/mongoid/maestrano_group_generator.rb +26 -0
  16. data/lib/generators/mongoid/maestrano_user_generator.rb +26 -0
  17. data/lib/maestrano/rails/controllers/maestrano_security.rb +32 -0
  18. data/lib/maestrano/rails/models/maestrano_auth_resource.rb +96 -0
  19. data/lib/maestrano/rails/version.rb +5 -0
  20. data/lib/maestrano/rails.rb +10 -0
  21. data/lib/maestrano-rails.rb +1 -0
  22. data/test/controllers/generic_controller_test.rb +54 -0
  23. data/test/controllers/saml_controller_test.rb +117 -0
  24. data/test/dummy/README.rdoc +261 -0
  25. data/test/dummy/Rakefile +7 -0
  26. data/test/dummy/app/assets/javascripts/application.js +15 -0
  27. data/test/dummy/app/assets/javascripts/pages.js +2 -0
  28. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  29. data/test/dummy/app/assets/stylesheets/pages.css +4 -0
  30. data/test/dummy/app/controllers/application_controller.rb +3 -0
  31. data/test/dummy/app/controllers/maestrano/auth/saml_controller.rb +14 -0
  32. data/test/dummy/app/controllers/pages_controller.rb +4 -0
  33. data/test/dummy/app/helpers/application_helper.rb +2 -0
  34. data/test/dummy/app/helpers/pages_helper.rb +2 -0
  35. data/test/dummy/app/models/admin/monster.rb +2 -0
  36. data/test/dummy/app/models/admin.rb +5 -0
  37. data/test/dummy/app/models/mno_crew.rb +7 -0
  38. data/test/dummy/app/models/mno_monster.rb +9 -0
  39. data/test/dummy/app/models/monster.rb +2 -0
  40. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/test/dummy/app/views/pages/home.html.erb +2 -0
  42. data/test/dummy/config/application.rb +56 -0
  43. data/test/dummy/config/boot.rb +10 -0
  44. data/test/dummy/config/database.yml +25 -0
  45. data/test/dummy/config/environment.rb +5 -0
  46. data/test/dummy/config/environments/development.rb +37 -0
  47. data/test/dummy/config/environments/production.rb +67 -0
  48. data/test/dummy/config/environments/test.rb +37 -0
  49. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test/dummy/config/initializers/inflections.rb +15 -0
  51. data/test/dummy/config/initializers/maestrano.rb +84 -0
  52. data/test/dummy/config/initializers/mime_types.rb +5 -0
  53. data/test/dummy/config/initializers/secret_token.rb +7 -0
  54. data/test/dummy/config/initializers/session_store.rb +8 -0
  55. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  56. data/test/dummy/config/locales/en.yml +5 -0
  57. data/test/dummy/config/routes.rb +70 -0
  58. data/test/dummy/config.ru +4 -0
  59. data/test/dummy/db/development.sqlite3 +0 -0
  60. data/test/dummy/db/migrate/20140526125222_create_monsters.rb +8 -0
  61. data/test/dummy/db/migrate/20140526125242_create_admin_monsters.rb +8 -0
  62. data/test/dummy/db/migrate/20140526144828_create_mno_monsters.rb +13 -0
  63. data/test/dummy/db/migrate/20140526151139_create_mno_crews.rb +11 -0
  64. data/test/dummy/db/schema.rb +44 -0
  65. data/test/dummy/db/test.sqlite3 +0 -0
  66. data/test/dummy/log/development.log +76 -0
  67. data/test/dummy/log/test.log +3732 -0
  68. data/test/dummy/public/404.html +26 -0
  69. data/test/dummy/public/422.html +26 -0
  70. data/test/dummy/public/500.html +25 -0
  71. data/test/dummy/public/favicon.ico +0 -0
  72. data/test/dummy/script/rails +6 -0
  73. data/test/dummy/test/fixtures/admin/monsters.yml +11 -0
  74. data/test/dummy/test/fixtures/mno_crews.yml +11 -0
  75. data/test/dummy/test/fixtures/mno_monsters.yml +15 -0
  76. data/test/dummy/test/fixtures/monsters.yml +11 -0
  77. data/test/dummy/test/functional/pages_controller_test.rb +9 -0
  78. data/test/dummy/test/unit/admin/monster_test.rb +7 -0
  79. data/test/dummy/test/unit/helpers/pages_helper_test.rb +4 -0
  80. data/test/dummy/test/unit/mno_crew_test.rb +7 -0
  81. data/test/dummy/test/unit/mno_monster_test.rb +7 -0
  82. data/test/dummy/test/unit/monster_test.rb +7 -0
  83. data/test/generators/group/active_record_generator_test.rb +79 -0
  84. data/test/generators/group/mongoid_generator_test.rb +76 -0
  85. data/test/generators/group_generator_test.rb +39 -0
  86. data/test/generators/install_generator_test.rb +36 -0
  87. data/test/generators/user/active_record_generator_test.rb +79 -0
  88. data/test/generators/user/mongoid_generator_test.rb +76 -0
  89. data/test/generators/user_generator_test.rb +39 -0
  90. data/test/maestrano-rails_test.rb +7 -0
  91. data/test/models/maestrano_group_via_test.rb +66 -0
  92. data/test/models/maestrano_user_via_test.rb +70 -0
  93. data/test/test_files/config/routes.rb +58 -0
  94. data/test/test_helper.rb +24 -0
  95. data/test/tmp/app/models/monster.rb +20 -0
  96. metadata +287 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Maestrano
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,164 @@
1
+ <p align="center">
2
+ <img src="https://raw.github.com/maestrano/maestrano-rails/master/maestrano.png" alt="Maestrano Logo">
3
+ </p>
4
+
5
+ Maestrano Cloud Integration is currently in closed beta. Want to know more? Send us an email to <contact@maestrano.com>.
6
+
7
+ ## Getting Setup
8
+ Before integrating with us you will need an API Key. Maestrano Cloud Integration being still in closed beta you will need to contact us beforehand to gain production access.
9
+
10
+ For testing purpose we provide an API Sandbox where you can freely obtain an API Token. The sandbox is great to test single sign-on and API integration (e.g: billing API).
11
+
12
+ To get started just go to: http://api-sandbox.maestrano.io
13
+
14
+ ## Getting Started
15
+
16
+ maestrano-rails works with Rails 3.2 onwards. You can add it to your Gemfile with:
17
+
18
+ ```ruby
19
+ gem 'maestrano-rails'
20
+ ```
21
+
22
+ Run bundle to install the gem as well as the [maestrano ruby bindings](https://github.com/maestrano/maestrano-ruby) (dependency)
23
+
24
+ ```console
25
+ bundle
26
+ ```
27
+
28
+ After you install Maestrano and add it to your Gemfile, you need to run the generator:
29
+
30
+ ```console
31
+ rails generate maestrano:install
32
+ ```
33
+
34
+ The generator will install an initializer which describes ALL Maestrano's configuration options. You will need to take a look at it as this is where you set your API key.
35
+ The generator also generates a SamlController for single sign-on that you will need to customize (see below) as well as the required routes.
36
+
37
+ When you are done, you can start maestrano-izing your user and group model using the generators.
38
+
39
+ ### User model
40
+ Assuming your user model is called 'User' you can run the following generator to prepare this model for single sign-on:
41
+
42
+ ```console
43
+ rails generate maestrano:user User
44
+ ```
45
+
46
+ This generator will create a migration adding a :provider and :uid field to your user model. If you are already using multi-auth strategies (using [omniauth](https://github.com/intridea/omniauth) for example) then you can just ignore and delete this migration.
47
+
48
+ Run the migration with:
49
+ ```console
50
+ bundle exec rake db:migrate
51
+ ```
52
+
53
+ This generator also adds a configuration block to your user model which looks like this:
54
+ ```ruby
55
+ class User < ActiveRecord::Base
56
+ # Enable Maestrano for this user
57
+ maestrano_user_via :provider, :uid do |user,maestrano|
58
+ user.name = maestrano.first_name
59
+ user.surname = maestrano.last_name
60
+ user.email = maestrano.email
61
+ #user.company = maestrano.company_name
62
+ #user.country_alpha2 = maestrano.country
63
+ #user.some_required_field = 'some-appropriate-default-value'
64
+ end
65
+
66
+ ...
67
+
68
+ end
69
+ ```
70
+
71
+ This block is used to create a mapping between your user model fields and the attributes provided by Maestrano during the single sign-on handshake.
72
+
73
+ ### Group model
74
+ Because Maestrano works with businesses it expects your service to be able to manage groups of users. A group represents 1) a billing entity 2) a collaboration group. During the first single sign-on handshake both a user and a group should be created. Additional users logging in via the same group should then be added to this existing group (see controller setup below)
75
+
76
+ Assuming your group model is called 'Organization' you can run the following generator to prepare this model for single sign-on:
77
+
78
+ ```console
79
+ rails generate maestrano:group Organization
80
+ ```
81
+
82
+ This generator will create a migration adding a :provider and :uid field to your group model.
83
+
84
+ Run the migration with:
85
+ ```console
86
+ bundle exec rake db:migrate
87
+ ```
88
+
89
+ This generator also adds a configuration block to your group model which looks like this:
90
+
91
+ ```ruby
92
+ class Organization < ActiveRecord::Base
93
+ maestrano_group_via :provider, :uid do |group,maestrano|
94
+ group.name = maestrano.company_name || "Your Group"
95
+ end
96
+
97
+ ...
98
+
99
+ end
100
+ ```
101
+
102
+ ### Controller setup
103
+ The last step of integrating single sign-on with Maestrano is to customize the consume action of the SamlController. This action represents the last step of single sign-on handshake and should handle user finding/creation, group finding/creation, user-group relationship and finally user sign in.
104
+
105
+ The controller is located here: app/controllers/maestrano/auth/saml_controller.rb
106
+
107
+ The sample belows shows one possible way of writing this controller action:
108
+
109
+ ```ruby
110
+ class Maestrano::Auth::SamlController < Maestrano::Rails::SamlBaseController
111
+
112
+ #== POST '/maestrano/auth/saml/consume'
113
+ # -
114
+ # Assuming you have enabled maestrano on a user model
115
+ # called 'User' and a group model called 'Organization'
116
+ # the action could be written the following way
117
+ def consume
118
+ # 1)Find or create the user and the group
119
+ # --
120
+ # The class method 'find_or_create_for_maestrano' is provided
121
+ # by the maestrano-rails gem on the model you have maestrano-ized.
122
+ # The method uses the mapping defined in the model 'maestrano_*_via'
123
+ # block to create the resource if it does not exist
124
+ # The 'user_auth_hash' and 'group_auth_hash' methods are provided
125
+ # by the controller.
126
+ # --
127
+ user = User.find_or_create_for_maestrano(user_auth_hash)
128
+ organization = Organization.find_or_create_for_maestrano(group_auth_hash)
129
+
130
+
131
+ # 2) Add the user to the group if not already a member
132
+ # --
133
+ # The 'user_group_rel_hash' method is provided by the controller.
134
+ # The role attribute provided by maestrano is one of the following:
135
+ # 'Member', 'Power User', 'Admin', 'Super Admin'
136
+ # The 'member_of?' and 'add_member' methods are not provided by
137
+ # maestrano and are left to you to implement on your models
138
+ # --
139
+ unless user.member_of?(organization)
140
+ organization.add_member(user,role: user_group_rel_hash[:role])
141
+ end
142
+
143
+
144
+ # Sign the user in and redirect to application root
145
+ # --
146
+ # The 'sign_in' method is not provided by maestrano but should already
147
+ # be there if you are using an authentication framework like Devise
148
+ # --
149
+ sign_in(user)
150
+ redirect_to root_path
151
+ end
152
+ end
153
+ ```
154
+
155
+ ## Support
156
+ This README is still in the process of being written and improved. As such it might not cover some of the questions you might have.
157
+
158
+ So if you have any question or need help integrating with us just let us know at support@maestrano.com
159
+
160
+ ## License
161
+
162
+ MIT License. Copyright 2014 Maestrano Pty Ltd. https://maestrano.com
163
+
164
+ You are not granted rights or licenses to the trademarks of Maestrano.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Maestrano-rails'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,39 @@
1
+ class Maestrano::Rails::SamlBaseController < ApplicationController
2
+ attr_reader :saml_response, :user_auth_hash, :group_auth_hash, :user_group_rel_hash
3
+ around_filter :saml_response_transaction, only: [:consume]
4
+
5
+ # Initialize the SAML request and redirects the
6
+ # user to Maestrano
7
+ def init
8
+ redirect_to Maestrano::Saml::Request.new(params,session).redirect_url
9
+ end
10
+
11
+ #===================================
12
+ # Helper methods
13
+ #===================================
14
+ def saml_response_transaction
15
+ begin
16
+ process_saml_response
17
+ yield
18
+ Maestrano::SSO.set_session(session,@user_auth_hash)
19
+ rescue Exception => e
20
+ logger.error e
21
+ redirect_to "#{Maestrano::SSO.unauthorized_url}?err=internal"
22
+ end
23
+ end
24
+
25
+ def process_saml_response
26
+ if params[:SAMLResponse]
27
+ @saml_response = Maestrano::Saml::Response.new(params[:SAMLResponse])
28
+ if @saml_response.validate!
29
+ @user_auth_hash = Maestrano::SSO::BaseUser.new(@saml_response).to_hash
30
+ @group_auth_hash = Maestrano::SSO::BaseGroup.new(@saml_response).to_hash
31
+ @user_group_rel_hash = {
32
+ user_uid: @saml_response.attributes['uid'],
33
+ group_uid: @saml_response.attributes['group_uid'],
34
+ role: @saml_response.attributes['group_role']
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails/generators/active_record'
2
+ require 'generators/maestrano/orm_helpers'
3
+
4
+ module ActiveRecord
5
+ module Generators
6
+ class MaestranoGroupGenerator < ActiveRecord::Generators::Base
7
+ include Maestrano::Generators::OrmHelpers
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def copy_maestrano_migration
11
+ migration_template "migration.rb", "db/migrate/add_maestrano_to_#{table_name}.rb"
12
+ end
13
+
14
+ def inject_maestrano_content
15
+ content = model_contents
16
+
17
+ class_path = if namespaced?
18
+ class_name.to_s.split("::")
19
+ else
20
+ [class_name]
21
+ end
22
+
23
+ indent_depth = class_path.size - 1
24
+ content = content.split("\n").map { |line| " " * indent_depth + line } .join("\n") << "\n"
25
+
26
+ inject_into_class(model_path, class_path.last, content) if model_exists?
27
+ end
28
+
29
+ def migration_data
30
+ <<RUBY
31
+ ## User source identification fields
32
+ t.string :provider
33
+ t.string :uid
34
+ RUBY
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails/generators/active_record'
2
+ require 'generators/maestrano/orm_helpers'
3
+
4
+ module ActiveRecord
5
+ module Generators
6
+ class MaestranoUserGenerator < ActiveRecord::Generators::Base
7
+ include Maestrano::Generators::OrmHelpers
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def copy_maestrano_migration
11
+ migration_template "migration.rb", "db/migrate/add_maestrano_to_#{table_name}.rb"
12
+ end
13
+
14
+ def inject_maestrano_content
15
+ content = model_contents
16
+
17
+ class_path = if namespaced?
18
+ class_name.to_s.split("::")
19
+ else
20
+ [class_name]
21
+ end
22
+
23
+ indent_depth = class_path.size - 1
24
+ content = content.split("\n").map { |line| " " * indent_depth + line } .join("\n") << "\n"
25
+
26
+ inject_into_class(model_path, class_path.last, content) if model_exists?
27
+ end
28
+
29
+ def migration_data
30
+ <<RUBY
31
+ ## User source identification fields
32
+ t.string :provider
33
+ t.string :uid
34
+ RUBY
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ class AddMaestranoTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table(:<%= table_name %>) do |t|
4
+ <%= migration_data -%>
5
+ end
6
+
7
+ def self.down
8
+ # By default, we don't want to make any assumption about how to roll back this migration.
9
+ # Please edit below which fields you would like to remove in this migration.
10
+ raise ActiveRecord::IrreversibleMigration
11
+ end
12
+ end
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Generates all files required to get your rails app setup with maestrano
@@ -0,0 +1,11 @@
1
+ module Maestrano
2
+ module Generators
3
+ class GroupGenerator < ::Rails::Generators::NamedBase
4
+ include ::Rails::Generators::ResourceHelpers
5
+
6
+ source_root File.expand_path("../templates", __FILE__)
7
+ desc "Configure group model <NAME> for maestrano and create migration"
8
+ hook_for :orm, as: :maestrano_group
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ module Maestrano
2
+ module Generators
3
+ class InstallGenerator < ::Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+ desc "Creates a Maestrano initializer and a customizable controller for SAML Single Sign-On"
6
+
7
+ def copy_initializer
8
+ template "maestrano.rb", "config/initializers/maestrano.rb"
9
+ end
10
+
11
+ def copy_saml_controller
12
+ template "saml_controller.rb", "app/controllers/maestrano/auth/saml_controller.rb"
13
+ end
14
+
15
+ def add_maestrano_routes
16
+ maestrano_routes = <<-CONTENT
17
+ namespace :maestrano do
18
+ namespace :auth do
19
+ resources :saml, only:[] do
20
+ get 'init', on: :collection
21
+ post 'consume', on: :collection
22
+ end
23
+ end
24
+ end
25
+ CONTENT
26
+ route maestrano_routes
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,75 @@
1
+ module Maestrano
2
+ module Generators
3
+ module OrmHelpers
4
+
5
+ def model_contents
6
+
7
+ if model_type == 'user'
8
+ buffer = <<-CONTENT
9
+ # Enable Maestrano for this user
10
+ maestrano_user_via :provider, :uid do |user,maestrano|
11
+ user.name = maestrano.first_name
12
+ user.surname = maestrano.last_name
13
+ user.email = maestrano.email
14
+ #user.company = maestrano.company_name
15
+ #user.country_alpha2 = maestrano.country
16
+ #user.some_required_field = 'some-appropriate-default-value'
17
+ end
18
+
19
+ CONTENT
20
+ else
21
+ buffer = <<-CONTENT
22
+ # Enable Maestrano for this group
23
+ maestrano_group_via :provider, :uid do |group, maestrano|
24
+ group.name = (maestrano.company_name || "Default Group name")
25
+ #group.country_alpha2 = maestrano.country
26
+ #group.free_trial_end_at = maestrano.free_trial_end_at
27
+ #group.some_required_field = 'some-appropriate-default-value'
28
+ end
29
+
30
+ CONTENT
31
+ end
32
+
33
+ buffer += <<-CONTENT if needs_attr_accessible?
34
+ # Setup protected attributes for your model
35
+ attr_protected :provider, :uid
36
+
37
+ CONTENT
38
+ buffer
39
+ end
40
+
41
+ def model_type
42
+ self.class.name.split("::").last.gsub("Maestrano","").gsub("Generator","").downcase
43
+ end
44
+
45
+ def needs_attr_accessible?
46
+ rails_3? && !strong_parameters_enabled?
47
+ end
48
+
49
+ def rails_3?
50
+ ::Rails::VERSION::MAJOR == 3
51
+ end
52
+
53
+ def strong_parameters_enabled?
54
+ defined?(ActionController::StrongParameters)
55
+ end
56
+
57
+ private
58
+ def model_exists?
59
+ File.exists?(File.join(destination_root, model_path))
60
+ end
61
+
62
+ def migration_exists?(table_name)
63
+ Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_maestrano_to_#{table_name}.rb$/).first
64
+ end
65
+
66
+ def migration_path
67
+ @migration_path ||= File.join("db", "migrate")
68
+ end
69
+
70
+ def model_path
71
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,84 @@
1
+ # Use this block to configure the behaviour of Maestrano
2
+ # in your app
3
+ Maestrano.configure do |config|
4
+
5
+ # ==> Environment configuration
6
+ # The environment to connect to.
7
+ # If set to 'production' then all Single Sign-On (SSO) and API requests
8
+ # will be made to maestrano.com
9
+ # If set to 'test' then requests will be made to api-sandbox.maestrano.io
10
+ # The api-sandbox allows you to easily test integration scenarios.
11
+ # More details on http://api-sandbox.maestrano.io
12
+ config.environment = Rails.env.production? ? 'production' : 'test'
13
+
14
+ # ==> API key
15
+ # Your application API key which you can retrieve on http://maestrano.com
16
+ # via your cloud partner dashboard.
17
+ # For testing you can retrieve/generate an api_key from the API Sandbox directly
18
+ # on http://api-sandbox.maestrano.io
19
+ config.api_key = Rails.env.production? ? 'prod_api_key' : 'sandbox_api_key'
20
+
21
+ # ==> Single Sign-On activation
22
+ # Enable/Disable single sign-on. When troubleshooting authentication issues
23
+ # you might want to disable SSO temporarily
24
+ config.sso_enabled = true
25
+
26
+ # ==> Application host
27
+ # This is your application host (e.g: mysuperapp.com) which is ultimately
28
+ # used to redirect users to the right SAML url during SSO handshake.
29
+ config.app_host = Rails.env.production? ? 'https://my-production-app.com' : 'http://localhost::3000'
30
+
31
+ # ==> SSO Initialization endpoint
32
+ # This is your application path to the SAML endpoint that allows users to
33
+ # initialize SSO authentication. Upon reaching this endpoint users your
34
+ # application will automatically create a SAML request and redirect the user
35
+ # to Maestrano. Maestrano will then authenticate and authorize the user. Upon
36
+ # authorization the user gets redirected to your application consumer endpoint
37
+ # (see below) for initial setup and/or login.
38
+ # The controller for this path is automatically
39
+ # generated when you run 'rake maestrano:install' and is available at
40
+ # <rails_root>/app/controllers/maestrano/auth/saml.rb
41
+ config.sso_app_init_path = '/maestrano/auth/saml/init'
42
+
43
+ # ==> SSO Consumer endpoint
44
+ # This is your application path to the SAML endpoint that allows users to
45
+ # finalize SSO authentication. During the 'consume' action your application
46
+ # sets users (and associated group) up and/or log them in.
47
+ # The controller for this path is automatically
48
+ # generated when you run 'rake maestrano:install' and is available at
49
+ # <rails_root>/app/controllers/maestrano/auth/saml.rb
50
+ config.sso_app_consume_path = '/maestrano/auth/saml/consume'
51
+
52
+ # ==> SSO User creation mode
53
+ # !IMPORTANT
54
+ # On Maestrano users can take several "instances" of your service. You can consider
55
+ # each "instance" as 1) a billing entity and 2) a collaboration group (this is
56
+ # equivalent to a 'customer account' in a commercial world). When users login to
57
+ # your application via single sign-on they actually login via a specific group which
58
+ # is then supposed to determine which data they have access to inside your application.
59
+ #
60
+ # E.g: John and Jack are part of group 1. They should see the same data when they login to
61
+ # your application (employee info, analytics, sales etc..). John is also part of group 2
62
+ # but not Jack. Therefore only John should be able to see the data belonging to group 2.
63
+ #
64
+ # In most application this is done via collaboration/sharing/permission groups which is
65
+ # why a group is required to be created when a new user logs in via a new group (and
66
+ # also for billing purpose - you charge a group, not a user directly).
67
+ #
68
+ # == mode: 'real'
69
+ # In an ideal world a user should be able to belong to several groups in your application.
70
+ # In this case you would set the 'user_creation_mode' to 'real' which means that the uid
71
+ # and email we pass to you are the actual user email and maestrano universal id.
72
+ #
73
+ # == mode: 'virtual'
74
+ # Now let's say that due to technical constraint your application cannot authorize a user
75
+ # to belong to several groups. Well next time John logs in via a different group there will
76
+ # be a problem: the user already exists (based on uid or email) and cannot be assigned
77
+ # to a second group. To fix this you can set the 'user_creation_mode' to 'virtual'. In this
78
+ # mode users get assigned a truly unique uid and email across groups. So next time John logs
79
+ # in a whole new user account can be created for him without any validation problem. In this
80
+ # mode the email we assign to him looks like "usr-sdf54.cld-45aa2@mail.maestrano.com". But don't
81
+ # worry we take care of forwarding any email you would send to this address
82
+ #
83
+ config.user_creation_mode = 'virtual' # or 'real'
84
+ end
@@ -0,0 +1,52 @@
1
+ class Maestrano::Auth::SamlController < Maestrano::Rails::SamlBaseController
2
+
3
+ #== POST '/maestrano/auth/saml/consume'
4
+ # Final phase of the Single Sign-On handshake. Find or create
5
+ # the required resources (user and group) and sign the user
6
+ # in
7
+ #
8
+ # This action is left to you to customize based on your application
9
+ # requirements. Below is presented a potential way of writing
10
+ # the action.
11
+ #
12
+ # Assuming you have enabled maestrano on a user model
13
+ # called 'User' and a group model called 'Organization'
14
+ # the action could be written the following way
15
+ def consume
16
+ ### 1)Find or create the user and the group
17
+ ### --
18
+ ### The class method 'find_or_create_for_maestrano' is provided
19
+ ### by the maestrano-rails gem on the model you have maestrano-ized.
20
+ ### The method uses the mapping defined in the model 'maestrano_*_via'
21
+ ### block to create the resource if it does not exist
22
+ ### The 'user_auth_hash' and 'group_auth_hash' methods are provided
23
+ ### by the controller.
24
+ ### --
25
+ # user = User.find_or_create_for_maestrano(user_auth_hash)
26
+ # organization = Organization.find_or_create_for_maestrano(group_auth_hash)
27
+ #
28
+ #
29
+ ### 2) Add the user to the group if not already a member
30
+ ### --
31
+ ### The 'user_group_rel_hash' method is provided by the controller.
32
+ ### The role attribute provided by maestrano is one of the following:
33
+ ### 'Member', 'Power User', 'Admin', 'Super Admin'
34
+ ### The 'member_of?' and 'add_member' methods are not provided by
35
+ ### maestrano and are left to you to implement on your models
36
+ ### --
37
+ # unless user.member_of?(organization)
38
+ # organization.add_member(user,role: user_group_rel_hash[:role])
39
+ # end
40
+ #
41
+ #
42
+ ### Sign the user in and redirect to application root
43
+ ### --
44
+ ### The 'sign_in' method is not provided by maestrano but should already
45
+ ### be there if you are using an authentication framework like Devise
46
+ ### --
47
+ # sign_in(user)
48
+ # redirect_to root_path
49
+
50
+ raise NotImplemented.new("The consume action should be customized to fit your application needs")
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ module Maestrano
2
+ module Generators
3
+ class UserGenerator < ::Rails::Generators::NamedBase
4
+ include ::Rails::Generators::ResourceHelpers
5
+
6
+ source_root File.expand_path("../templates", __FILE__)
7
+ desc "Configure user model <NAME> for maestrano and create migration"
8
+ hook_for :orm, as: :maestrano_user
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails/generators/named_base'
2
+ require 'generators/maestrano/orm_helpers'
3
+
4
+ module Mongoid
5
+ module Generators
6
+ class MaestranoGroupGenerator < Rails::Generators::NamedBase
7
+ include Maestrano::Generators::OrmHelpers
8
+
9
+ def inject_field_types
10
+ inject_into_file model_path, migration_data, after: "include Mongoid::Document\n" if model_exists?
11
+ end
12
+
13
+ def inject_maestrano_content
14
+ inject_into_file model_path, model_contents, after: "include Mongoid::Document\n" if model_exists?
15
+ end
16
+
17
+ def migration_data
18
+ <<RUBY
19
+ ## User source identification fields
20
+ field :provider, type: String, default: ""
21
+ field :uid, type: String, default: ""
22
+ RUBY
23
+ end
24
+ end
25
+ end
26
+ end