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

07/12/06 02:32:37 (13 years ago)

Revert to version 70


  • IdentityManagement

    v73 v74  
    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. 
     14$ tg-admin quickstart  
     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.   
     19After you specified the project name. a identity prompt will pop up: 
     22Do you need Identity (usernames/passwords) in this project? [no] 
     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:  
     28Select your provider sqlobject or sqlalchemy [sqlobject]: 
     31We should choose SQL Object, this will generate the identity-related code.  
     34== B. Setting up Identity == 
     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 
     40To take advantage of identity, we need enable it. 
     44=== Step 1 - Testing the login === 
     45Now let's check whether we have all set up correctly so far. Start the project as usual: 
     49$ start-identity_tutorial 
     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. 
     54You can access any other page without trouble, because we haven't protected those pages yet. 
     56=== Step 2 - Adding an initial user and group === 
     58Of course, we will need at least one group and one user account to work with. Let's create these with CatWalk 
     60Start {{{Turbogears}}} toolbox 
     63$tg-admin toolbox 
     66Enter CatWalk. You should see the TG_Group, TG_Permission, and TG_User classes on the left side. 
     68==== a) Create a user ==== 
     69Select TG_User. Click the "Add TG_User+" button, then enter the user information. For example: 
     72displayName : Jane Doe 
     73userId : jdoe 
     74emailAddress : jdoe@example.com 
     75password : xxx 
     78Click "Save". 
     80==== b) Create an admin group ==== 
     81Select TG_Group. Click the "Add TG_Group+" button. Enter the displayName and groupId, for example: 
     84displayName : Administrators 
     85groupId :admin 
     88Click "Save". 
     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. 
     95== C. Using Identity in the Controller == 
     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. 
     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: 
     103    @turbogears.expose(template=".templates.welcome") 
     104    @identity.require(identity.in_group("admin")) 
     105    def index(self): 
     106        ... 
     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. 
     111Note that identity has added a small "Welcome, Jane Doe. Logout" at the top of the page. 
     113== D. Identity Predicates == 
     115=== Single Permission Checks === 
     117==== Checking that the user is logged in ==== 
     124==== Checking access groups ==== 
     130Many people wanted something more flexible, any of the following are valid require decorators: 
     134@identity.require(identity.in_all_groups("admin", "editor")) 
     136@identity.require(identity.in_any_group("admin", "editor")) 
     139==== Checking access permissions ==== 
     145@identity.require(identity.has_all_permissions("edit", "delete", "update")) 
     147@identity.require(identity.has_any_permission("edit", "delete", "update")) 
     150==== Checking hosts ==== 
     155@identity.require(identity.from_any_host(("", ""))) 
     158=== Combining Predicates === 
     160You can combine several predicates using {{{identity.Any}}} and {{{identity.All}}}: 
     164     @identity.require(identity.Any(identity.in_group("admin"), identity.has_permission("edit"))) 
     167This decorator grants access to members of the "admin" group as well as any user who has the "edit" permission. 
     171     @identity.require(identity.All(identity.from_host(""), identity.has_permission("edit"))) 
     173     @identity.require(identity.All(identity.from_any_host(("", "")), identity.in_group("editor"))) 
     181= Part II: Fine-Tuning Identity = 
     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. 
     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. 
     189=== Step 1. Import turbogears.identity === 
     191Make sure you import turbogears.identity in your template (anywhere before you call the turbogears.identity) 
     194<?python from turbogears import identity ?> 
     197===  Step 2. Conditional display  === 
     199Now we can use for example "py:if" attributes to display parts of the page depending on identity information: 
     201==== Using access groups ==== 
     203<a py:if="'admin' in identity.current.groups" href="/admin">This is a link for admin</a> 
     206==== Using access permissions ==== 
     208<div py:if="'write' in identity.current.permissions">This is a write permissions area</div> 
     211#TODO: Describe how to display user information 
     213===  Step 3. Displaying user information  === 
     216== B. More Access Checking Options == 
     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. 
     221=== 1. Protect your sub-directory === 
     223To restrict access to an entire controller (subdirectory), derive your Controller from identity.SecureResource and add a require attribute at the class level. 
     227class MySecureController(turbogears.Controller, identity.SecureResource): 
     228    require = identity.in_group("admin") 
     230    # etc. ...  
     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. 
     236=== 2. Check the permissions explicitly === 
     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. 
     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:  
     246class MyController(controllers.Controller, identity.SecureResource): 
     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")) 
     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. 
     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. 
     259You can also use the identity predicates in your own code: 
     262     if identity.in_group("admin") and identity.has_permission("edit"): 
     263         pass 
     264     else: 
     265         pass 
     270=== 3. Write your own decorator function === 
     272This is not for the faint at heart. But it gives you absolute flexibility.  
     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. 
     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. 
     281= Part III: Advanced Identity = 
     283== A. Using a Custom Identity Model == 
     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. 
     288There are some elements of the tables that you should not remove or rename.    
     290== B. Retrieve logged users' identity infomation == 
     292=== 1. Retrieve user identity infomation === 
     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. 
     296=== 2. Retrieve users’ group identity infomation === 
     298There are two ways to access the group information. 
     300'''1'''. Via the current identity object: 
     303from turbogears import identity 
     304if 'admin' in identity.current.groups: 
     305    pass 
     308'''2'''. Via the user object on the current identity: 
     311from turbogears import identity 
     312if 'admin' in [g.group_name for g in identity.current.user.groups]: 
     313    pass 
     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.'' 
     319== C. Adding user and group via tg-admin shell == 
     321Use "tg-admin shell" if you can't get Catwalk set up. 
     323This section can also serve as an example how to add users and groups programmatically.   
     328$ tg-admin shell 
     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() 
     339=== Add the user to admin group === 
     342$ tg-admin shell 
     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() 
    14353== D. Authenticating against an external password source ==