-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFAQ
More file actions
392 lines (271 loc) · 15.1 KB
/
Copy pathFAQ
File metadata and controls
392 lines (271 loc) · 15.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
=Repertoire Core FAQ=
Q. How do I change the layout for the registration/etc pages, respond-to email
address?
A. In init.rb:
Merb::BootLoader.before_app_loads do
Merb::Slices::config[:repertoire_core][:layout] ||= :my_admin_layout # layout for your own registration/password pages
Merb::Slices::config[:repertoire_core][:email_from] ||= 'repertoire@mit.edu'
end
Q. How do I add or replace user lookup services?
A. By default, records the domain of the user's email as their insitutional
affiliation. This allows it to associate users with institutions, robustly
offloading the task of checking credentials and other security to the
institution's email login system. To add another user identification service,
declare a helper class that updates the user's fields and returns a non-nil
value on success.
Merb::BootLoader.before_app_loads do
Merb::Slices::config[:repertoire_core][:lookup_helpers] << lambda do |user|
case user.email # a real example would probably access an outside directory service (e.g. ldap or finger)
when /@mit.edu$/: user.institution_code = "MIT"
else nil
end
end
The lookup handler polls helpers in order, stopping when one succeeds. You can
clear the list of handlers to disable lookup, replace it with you own to
disable the defaults, or rearrange the polling order.
Q. How do I use a different SMTP mail server?
A. In init.rb:
Merb::BootLoader.before_app_loads do
....
Merb::Mailer.config = {
:host => 'smtp.gmail.com', # example: use google mail smtp instead of MIT
:port => '587',
:user => 'repertoire.hyperstudio',
:pass => '77MassAve',
:auth => :plain
}
end
Q. How do I add project-specific information about users to the data model?
A. This is why Repertoire Core mixes its own fields into your user model.
Simply add a new table to store your per-project info, and then add an
association to the user model in your application. For example,
class User
include DataMapper::Resource
include RepertoireCore::Mixins::User
property :id, Serial
has n, :enrollments # project-specific
has n, :courses, :through => :enrollments # ditto
end
You can also add your own methods to the user model. Don't add new properties:
instead use a 1-to-1 relation to your project-specific user data, which is
stored in your project's PostgreSQL schema.
Q. How do I redirect to another URL after user activation (or signup/password
reset/etc.)?
A. The same way that merb-auth-password-slice allows you to define 'after'
controller filters to redirect on login and logout. Repertoire Core comes with
controller stubs set up for exactly this. Install them with 'rake
slices:repertoire_core:stubs' and modify the controller mixins in the
'slices/repertoire_core' directory.
Q. How do I show feedback from the Repertoire Core
registration/activation/etc. pages on my own?
A. Look in message[:notice] and message[:error]
Q. The default registration/profile/password pages are plain and ugly. How do
I reconfigure them?
A. Override the default CSS in your project's stylesheets. First set the
layout to your own project-specific design. Then define a new containing id to
surround the entire page contents. Define CSS styles relative to it. These
styles will always override the ones defined in the Repertoire Core files. You
can also use jquery to add new functionality to the existing pages. Or see
Merb slice documentation for info on completely over-riding views.
Q. How to remove unwanted information from the user profile pages.
A. Use display:none in your application's css.
Q. Can I access Repertoire core's administrative functions as a web service?
A. Yes. The controller methods are written to render HTML pages or for use
with ajax web services. With the exception of the form validation actions, the
latter approach is untested, however.
Q. How do I get the default login page to use same layout as the rest of the
pages?
A. The login page uses the application layout unless specified otherwise. You
can copy the Repertoire core layout into your layouts directory if necessary.
Q. Is there a way to replace Gravitar for user profile pictures? The extra
registration step is annoying.
A. No support yet. But it's possible to revise the profile page with a file
upload, then use ImageScience to thumbnail the picture. It's unclear as of
yet, however, where to store cross-project assets like these files. So that
issue would need to be solved.
Q. Is there a quick way to reset a user's password?
A. Easiest way is to have them use the password reset by email feature. BUT,
in a pinch you can use the model API to modify accounts:
# merb -i
>> u = User.first(:email => 'user@company.com')
>> u.password = u.password_confirmation = 'NEWPASSWORD'
>> u.save!
There's absolutely no way to see a user's current password, since both it and
the salt are md5 encrypted. However, you can do all basic user admin from the
command line, including creating accounts, activating them, resetting
passwords, and granting roles. See the User model API for details.
Q. How do I require login for a given page?
A. Repertoire core delegates authentication to the merb-auth-slice-password
plugin. The README in its source will give detailed information. But in
general, in routes.rb:
authenticate do
resource :posts
end
Q. How do I require authorization for a given page?
A. (1) Call require_role! at the beginning of your action:
def delete_em_all
require_role!(:foo_role)
...
end
(2) Use a before filter to protect all actions in a controller:
before :ensure_authorized, :with => [:system_administrator, :message => 'You need sysadmin role to remove the hard drive']
If you provide a list of roles, any match will allow access. You can also
pass :message => 'foo' to require_role! (in fact, require_role! and
ensure_authorized are aliases)
Q. Sure, that provides access control over actions, but what's the best way to
avoid presenting users with the unavailable options in the first place?
A. The most direct way is with conditional erb:
<% if session.user.has_role?(:sysadmin) %>
<div id="delete_everything_tab">...</div>
<% end %>
But over time that litters your views with progressively more and more
authorization logic. Another approach is to offload the task to css. List all
of the user's role names in classes on a containing div, and display only the
controls that are valid for the user's given roles:
... In the view:
<div class="sysadmin ber_member"> <!-- complete list of user's roles. there's a view helper:
<div class="<%= roles_css(session.user) %>">... -->
<div id="delete_everything_tab" class="control">...</div> <!-- only for admins -->
<div id="contribute_tab" class="control">...</div> <!-- only for members -->
<div id="browse_tab" class="control">...</div> <!-- for guests and others -->
</div>
... In the css:
.control { display: none; } /* default to controls invisible */
.sysadmin #delete_everything_tab { display: block; } /* visible to sysadmins */
.ber_member #contribute_tab { display: block; } /* visible to ber_members */
.guest #browse_tab { display: block; } /* visible to guests */
The advantage to this is that it's completely declarative, easy to maintain,
and keeps logic out of your views. The downside is that users can see your
application's security structure in the html source. (But you did declare
authorization filters on the controller to actually keep them out, right?...)
Q. How to link to the admin pages from my project?
A. Write links in your own view code where is most appropriate for your
project's graphic design. In particular, you may wish to link to the role
subscription page at appropriate places in your views, to suggest how users
can get increased access. This is why the subscription page expects to have
role_name pre-populated: send the right one in according to context. Then all
the user needs to do is enter a note and click subscribe.
Q. Does Repertoire core have routing extensions, only in-controller methods
for doing authorization?
A. For now, only controller filters. In general one wants to provide different
levels access to methods on the same controller (e.g. guests can browse posts,
but only members can add, and managers delete). Given this, your best bet
might be a single filter for base authentication (guest), and then to stick to
require_role! inside actions.
Q. How do I make a role closed to subscription or granting (other than what I
do by fiat in the console)? Conversely, how do I make a role that can be
joined without a review process.
A. granted_by not set | granted_by is set
---------------------|----------------------------
not subscribable | closed membership | can only be granted
subscribable | open membership | can be subscribed & granted
(pending review)
Or, here is a bit of RBAC haiku:
Role.declare do
Role[:admin]. # closed membership
grants(:manager). # can be granted
grants(:member).open. # can be subcribed & granted
# (pending review)
implies(:guest).open # open membership
end
Q. I want all of my project managers to be able to grant the member role, but
when someone subscribes to it only one or two designated reviewers should be
emailed.
A. One way to do it:
Role.declare do
Role[:proj_reviewer]. # role for reviewing membership requests
grants(:proj_member).open
Role[:proj_manager]. # separate manager role
implies(:proj_member)
end
Q. Is there only a single namespace for roles, across all projects?
A. Yes. Early versions of the data model included a "project context" field
that identified each role's project. But it quickly became clear that the
project context and role name only occur together, and serve to identify a
single system role. Plus it invited confusion: does "editor" in project "aop"
mean the same thing as "editor" in project "ter"? Probably not.
The conclusion was to use a single namespace for roles, and encourage projects
to use prefixes: :ber_editor, cfrp_contributor, etc.
Q. How would I set up a site-licensing system?
A. Site-licensing has the advantage that it has low administrative overhead,
since it lets users in based on their institutional identity. You probably
don't want to embed licensed insitutions' codes directly in your software
however. For slightly better system you'll want to store the site licenses in
the database model (say, SiteLicense), have a simple admin UI, and a single
role for managing licenses.
model:
class SiteLicense
include DataMapper::Resource
property :id, Serial
property :institution_code, String
end
migration:
Role.declare do
Role[:prj_license_manager]
end
Create a resource to mange site licenses - listing, viewing, adding, deleting,
etc. Authorize access only to your :prj_license_manager role. Then in a before
filter load up the currently active site licenses and use them to check users'
institution codes:
controller:
before :check_site_licenses
def check_site_licenses
codes = SiteLicense.all.map { |license| license.institution_code }
require_institution codes
end
At some point it would be nice to package up this functionality so it can be
installed easily in any project.
Q. How do I change the url in an approval or grant email to something specific
to the role granted? This way the user could see new functionality immediately
upon logging in
A. There are no provisions for this (yet!)
Q. What order do roles appear in the membership UI pages? It's not
alphabetical.
A. More privileged roles will appear earlier, and related roles are grouped
together. See Role#sort_order.
Q. Is Repertoire RBAC "true" role-based access control?
A. No. Its data model is slightly simpler to match our project model, and it
has better support for subscription. (1) RBAC as defined by NIST also includes
a notion of individual "permissions" that are reconfigured into roles as
institutional organization changes. That's a level of abstraction we don't
need: each project can be relatively sure of the roles it expects its users to
fulfil, so we just check roles directly. (2) Repertoire arranges roles into a
hierarchy, which isn't necessarily a requirement of NIST RBAC. (3) Repertoire
roles only grant access, they never deny it. This avoids logical conundrums
and the need for hueristics. (4) Traditional RBAC has no workflow for
subscribing or requesting a role that one doesn't have.
Q. My project has a concept of "groups." Should I use Repertoire core roles to
model this?
A. Probably not. Repertoire RBAC is designed to handle one thing -
authorization - and to do it well. If you need to model community
relationships, institutional structures, friendships, courses, or other
connections between people, it's best to develop a domain specific model.
One way to think of it is that RBAC roles best define the user's relationship
to system resources, not to other users. Often when the term "groups" comes up
in a design it's a sign of an ill-defined problem, and it's worth probing
deeper for the specific user activities the software should enable, and
modeling those. Usually it becomes obvious the group is actually a logical
aggregation of other data characteristics -- all workers with the same
employer, or all students enrolled in the same course.
=Common Problems=
Q. I can't get Merb's login page to work, even though the registration and
activation process is fine and I can find the user in the console.
A. Make sure merb-auth is configured to use User.email to identify users (in
merb/merb-auth/setup.rb)
Q. Merb is ignoring my authorization filters, and passing requests through
without checks!
A. After a revision in 10/2008, Merb now only allows a single filter
declaration per method. So
before :ensure_authorized, :with => [ :itm_manager, {:message => 'Manager right necessary to delete ' }]
before :ensure_authorized, :with => [ :itm_member, {:message => 'Please sign up to browse materials' }]
doesn't do what you expect! Only the final filter remains in place. The best
solution is to use require_role in your actions.
Q. I get a SMTP socket error when I test the registration pages on my
workstation.
A. The system must have internet access in order to send emails. (Not a
problem on a production install, since the registration pages are only
available via the internet).
Q. The system isn't sending my emails.
A. Check your sendmail configuration on this particular machine.
Q. I'm getting a "controller not found" exception when I try the default routes like signup! What's going on?
A. It's likely you've placed the router configuration underneath the default routes for your application. In this case, the router will catch these here first--you just have to move your repertoire router rules up higher.