Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Changes between Version 73 and Version 74 of IdentityManagement


Ignore:
Timestamp:
07/12/06 02:32:37 (13 years ago)
Author:
joey
Comment:

Revert to version 70

Legend:

Unmodified
Added
Removed
Modified
  • IdentityManagement

    v73 v74  
    1010 
    1111To begin with the tutorial, let's quick-start a learning project. Of course, everything you learn in the tutorial applies to existing projects as well. 
    12  
     12{{{ 
     13#!python 
     14$ tg-admin quickstart  
     15}}} 
     16 
     17Name your project "identity_tutorial" and set the database uri in "identity_tutorial/dev.cfg" to point to a server and database you want to use.   
     18 
     19After you specified the project name. a identity prompt will pop up: 
     20 
     21{{{ 
     22Do you need Identity (usernames/passwords) in this project? [no] 
     23}}} 
     24 
     25This tutorial wouldn't go very far if we didn't enable identity, so go ahead and type "yes". Next, it will ask us to select one of providers:  
     26 
     27{{{ 
     28Select your provider sqlobject or sqlalchemy [sqlobject]: 
     29}}} 
     30 
     31We should choose SQL Object, this will generate the identity-related code.  
     32 
     33 
     34== B. Setting up Identity == 
     35 
     36Identity Management can be used in controllers and in templates: 
     37 * In ''controllers'' to implement access restrictions 
     38 * In ''templates'' to adapt the appearance depending on the user's identity 
     39 
     40To take advantage of identity, we need enable it. 
     41 
     42 
     43 
     44=== Step 1 - Testing the login === 
     45Now let's check whether we have all set up correctly so far. Start the project as usual: 
     46 
     47{{{ 
     48#!python 
     49$ start-identity_tutorial 
     50}}} 
     51 
     52Visit the login page http://localhost:8080/login. You should see a pretty login page with username and password fields. Try to log in. It should fail with an error message since you haven't added any users/groups/permisions yet. 
     53 
     54You can access any other page without trouble, because we haven't protected those pages yet. 
     55 
     56=== Step 2 - Adding an initial user and group === 
     57 
     58Of course, we will need at least one group and one user account to work with. Let's create these with CatWalk 
     59 
     60Start {{{Turbogears}}} toolbox 
     61 
     62{{{ 
     63$tg-admin toolbox 
     64}}} 
     65 
     66Enter CatWalk. You should see the TG_Group, TG_Permission, and TG_User classes on the left side. 
     67 
     68==== a) Create a user ==== 
     69Select TG_User. Click the "Add TG_User+" button, then enter the user information. For example: 
     70 
     71{{{ 
     72displayName : Jane Doe 
     73userId : jdoe 
     74emailAddress : jdoe@example.com 
     75password : xxx 
     76}}} 
     77 
     78Click "Save". 
     79 
     80==== b) Create an admin group ==== 
     81Select TG_Group. Click the "Add TG_Group+" button. Enter the displayName and groupId, for example: 
     82 
     83{{{ 
     84displayName : Administrators 
     85groupId :admin 
     86}}} 
     87 
     88Click "Save". 
     89 
     90==== c) Add the new user to the admin group ==== 
     91Note that we are now in the "Browse" tab, with the new group displayed. 
     92Click the expansion triangle in front of "groups". This will reveal a "Manage Relations" link. Click on it. CatWalk will display two lists. Select the new user on the right list and click on "Add Selected" to move it to the left list. Then click "Save" to confirm the change. 
     93 
     94 
     95== C. Using Identity in the Controller == 
     96 
     97If you want to protect any method, add an {{{@identity.require(...)}}} decorator to the method. This decorator has a single argument, the ''predicate'', which specifies the conditions to check. The identity module provides many predicates that you can use. 
     98 
     99For example to protect the index page so that only members of the admin group can access it, we can use the {{{identity.in_group("admin")}}} predicate: 
     100 
     101{{{ 
     102#!python 
     103    @turbogears.expose(template=".templates.welcome") 
     104    @identity.require(identity.in_group("admin")) 
     105    def index(self): 
     106        ... 
     107}}} 
     108 
     109Let's try this now. Visit  http://localhost:8080/. As the index page is protected, you will be redirected to the login page. Log in using the name and password of the account which you previosly created. Now you should see the index page. 
     110 
     111Note that identity has added a small "Welcome, Jane Doe. Logout" at the top of the page. 
     112 
     113== D. Identity Predicates == 
     114 
     115=== Single Permission Checks === 
     116 
     117==== Checking that the user is logged in ==== 
     118{{{ 
     119#!python 
     120@identity.require(identity.not_anonymous()) 
     121}}} 
     122 
     123 
     124==== Checking access groups ==== 
     125{{{ 
     126#!python 
     127@identity.require(identity.in_group("admin")) 
     128}}} 
     129 
     130Many people wanted something more flexible, any of the following are valid require decorators: 
     131 
     132{{{ 
     133#!python 
     134@identity.require(identity.in_all_groups("admin", "editor")) 
     135 
     136@identity.require(identity.in_any_group("admin", "editor")) 
     137}}} 
     138 
     139==== Checking access permissions ==== 
     140 
     141{{{ 
     142#!python 
     143@identity.require(identity.has_permission("edit")) 
     144 
     145@identity.require(identity.has_all_permissions("edit", "delete", "update")) 
     146 
     147@identity.require(identity.has_any_permission("edit", "delete", "update")) 
     148}}} 
     149 
     150==== Checking hosts ==== 
     151{{{ 
     152#!python 
     153@identity.require(identity.from_host("127.0.0.1")) 
     154 
     155@identity.require(identity.from_any_host(("127.0.0.1", "10.0.0.1"))) 
     156}}} 
     157 
     158=== Combining Predicates === 
     159 
     160You can combine several predicates using {{{identity.Any}}} and {{{identity.All}}}: 
     161 
     162{{{ 
     163#!python 
     164     @identity.require(identity.Any(identity.in_group("admin"), identity.has_permission("edit"))) 
     165}}} 
     166 
     167This decorator grants access to members of the "admin" group as well as any user who has the "edit" permission. 
     168 
     169{{{ 
     170#!python 
     171     @identity.require(identity.All(identity.from_host("127.0.0.1"), identity.has_permission("edit"))) 
     172 
     173     @identity.require(identity.All(identity.from_any_host(("127.0.0.1", "10.0.0.1")), identity.in_group("editor"))) 
     174}}} 
     175 
     176 
     177---- 
     178 
     179 
     180 
     181= Part II: Fine-Tuning Identity = 
     182 
     183== A. Using Identity in Templates == 
     184Identity checks can also be used in kid templates to customize the appearance of the page depending on the user's identity. For example, you might show links to administrative functions only if the user is an administrator. 
     185 
     186'''Note''':  Identity checks in the template don't provide any security, as it is always possible to enter URLs directly.  
     187Therefore you shouldn't rely on identity checks in the template for your site's security. Always check the identity in the controller as described above. 
     188 
     189=== Step 1. Import turbogears.identity === 
     190 
     191Make sure you import turbogears.identity in your template (anywhere before you call the turbogears.identity) 
     192 
     193{{{ 
     194<?python from turbogears import identity ?> 
     195}}} 
     196 
     197===  Step 2. Conditional display  === 
     198 
     199Now we can use for example "py:if" attributes to display parts of the page depending on identity information: 
     200 
     201==== Using access groups ==== 
     202{{{ 
     203<a py:if="'admin' in identity.current.groups" href="/admin">This is a link for admin</a> 
     204}}} 
     205 
     206==== Using access permissions ==== 
     207{{{ 
     208<div py:if="'write' in identity.current.permissions">This is a write permissions area</div> 
     209}}} 
     210 
     211#TODO: Describe how to display user information 
     212 
     213===  Step 3. Displaying user information  === 
     214 
     215 
     216== B. More Access Checking Options == 
     217 
     218Sometimes, just restricting access to individual methods (pages) isn't enough. 
     219For example, you might want to protect an entire controller, or maybe your access permissions depend on the data viewed. 
     220 
     221=== 1. Protect your sub-directory === 
     222 
     223To restrict access to an entire controller (subdirectory), derive your Controller from identity.SecureResource and add a require attribute at the class level. 
     224 
     225{{{ 
     226#!python 
     227class MySecureController(turbogears.Controller, identity.SecureResource): 
     228    require = identity.in_group("admin") 
     229 
     230    # etc. ...  
     231}}} 
     232 
     233You can apply whatever decorators you want on the methods of the MySecureController instance. So each method could have additional restrictions. And MySecureController could have SecureObjects as well. However, access to exposed methods of MySecureController and any SecureObjects would have to satisfy the authorisation requirements for MySecureController. 
     234 
     235 
     236=== 2. Check the permissions explicitly === 
     237 
     238Let's say you are creating a web site where users can add their own content, like a blogging tool or a photo sharing site. Users should be able to edit their own content, but not the content added by other users. 
     239You can't do these checks in a decorator, as you need access to the actual data, which is only loaded in the method body. (And you don't want to load the data twice.) 
     240So you'll have to perform the identity checks in the method body. 
     241 
     242Again, derive your controller from identity.SecureResource. Perform your identity check at the method level. If the user doesn't have the required permissions, throw a suitable IdentityException:  
     243 
     244{{{ 
     245#!python 
     246class MyController(controllers.Controller, identity.SecureResource): 
     247 
     248     @turbogears.expose(html="mytemplate") 
     249     def myFunction(self): 
     250         if not ("admin" in identity.current.groups or 
     251                 "super" in identity.current.groups): 
     252             raise identity.GroupMembershipRequiredException(("admin", "super")) 
     253}}} 
     254 
     255This will work because SecureResource wraps all exposed methods with code that checks permissions and traps IdentityExceptions. So if your code, raises an IdentityException, everything will be handled correctly. 
     256 
     257Of course, you can then pull your authorisation logic out into a function that you call rather than copying and pasting it into each function that requires it. 
     258 
     259You can also use the identity predicates in your own code: 
     260{{{ 
     261#!python 
     262     if identity.in_group("admin") and identity.has_permission("edit"): 
     263         pass 
     264     else: 
     265         pass 
     266 
     267}}} 
     268 
     269 
     270=== 3. Write your own decorator function === 
     271 
     272This is not for the faint at heart. But it gives you absolute flexibility.  
     273 
     274Take a look at the decorators in turbogears/identity/conditions.py. They'll give you a head-start on what you'll have to do. 
     275 
     276Also, to make your life easier, remember using turbogears.decorator.  It will give you a solid basis and is used in other default decorators as well. 
     277 
     278---- 
     279 
     280 
     281= Part III: Advanced Identity = 
     282 
     283== A. Using a Custom Identity Model == 
     284 
     285Identity model classes are now placed directly into the "model.py" of a quickstarted project. 
     286You can customize your own classes for users, groups, and/or permissions -- to add a few attributes to the user class, say an image of the user and a phone number -- or even a complete replacement. 
     287 
     288There are some elements of the tables that you should not remove or rename.    
     289 
     290== B. Retrieve logged users' identity infomation == 
     291 
     292=== 1. Retrieve user identity infomation === 
     293 
     294We can access the entire User object by accessing "turbogears.identity.current.user" to get user identity infomation. This gives you access to the user_name, display_name, email_address, and creation date. 
     295 
     296=== 2. Retrieve users’ group identity infomation === 
     297 
     298There are two ways to access the group information. 
     299 
     300'''1'''. Via the current identity object: 
     301{{{ 
     302#!python 
     303from turbogears import identity 
     304if 'admin' in identity.current.groups: 
     305    pass 
     306}}} 
     307 
     308'''2'''. Via the user object on the current identity: 
     309{{{ 
     310#!python 
     311from turbogears import identity 
     312if 'admin' in [g.group_name for g in identity.current.user.groups]: 
     313    pass 
     314}}} 
     315 
     316''Option number 2 only works if your using a Model that supports groups on the user object. So, with the default model you’ll be set. Other models might not work so well.'' 
     317---- 
     318 
     319== C. Adding user and group via tg-admin shell == 
     320 
     321Use "tg-admin shell" if you can't get Catwalk set up. 
     322 
     323This section can also serve as an example how to add users and groups programmatically.   
     324 
     325 
     326{{{ 
     327#!python 
     328$ tg-admin shell 
     329 
     330>>> from turbogears.identity.soprovider import * 
     331>>> hub.begin() 
     332>>> u=TG_User(user_name="jeff", email_address="jeff@metrocat.org", 
     333            display_name="Jeff Watkins", password="xxxxx") 
     334>>> g=TG_Group(group_name="admin", display_name="Administrators") 
     335>>> hub.commit() 
     336>>> 
     337}}} 
     338 
     339=== Add the user to admin group === 
     340{{{ 
     341#!python 
     342$ tg-admin shell 
     343 
     344>>> from turbogears.identity.model.somodel import * 
     345>>> hub.begin() 
     346>>> u=TG_User.get(1) 
     347>>> g=TG_Group.get(1) 
     348>>> u.addTG_Group(g) 
     349>>> hub.commit() 
     350>>> 
     351}}} 
    13352 
    14353== D. Authenticating against an external password source ==