Provided by: python-fedora-doc_0.10.0-2_all bug

NAME

       python-fedora - python-fedora 0.10.0

       The  python-fedora  module  makes it easier for programmers to create both Fedora Services
       and clients that talk to the services.  It's licensed under the GNU Lesser General  Public
       License version 2 or later.

FEDORA CLIENT

       Authors
              Toshio Kuratomi Luke Macken

       Date   28 May 2008

       For Version
              0.3.x

       The client module allows you to easily code an application that talks to a Fedora Service.
       It handles the details of decoding the data sent from  the  Service  into  a  python  data
       structure and raises an Exception if an error is encountered.

   BaseClient
       The  BaseClient  class  is  the  basis  of  all  your interactions with the server.  It is
       flexible enough to be used as is for talking with a service but  is  really  meant  to  be
       subclassed  and  have  methods  written for it that do the things you specifically need to
       interact with the Fedora Service  you  care  about.   Authors  of  a  Fedora  Service  are
       encouraged  to  provide  their  own subclasses of BaseClient that make it easier for other
       people to use a particular Service out of the box.

   Using Standalone
       If you don't want to subclass, you can use BaseClient as a utility class to  talk  to  any
       Fedora  Service.   There's  three  steps  to  this.   First  you import the BaseClient and
       Exceptions from the fedora.client module.  Then you create a new BaseClient with  the  URL
       that  points  to  the  root  of  the Fedora Service you're interacting with.  Finally, you
       retrieve data from a method on the server.  Here's some code that illustrates the process:

          from fedora.client import BaseClient, AppError, ServerError

          client = BaseClient('https://admin.fedoraproject.org/pkgdb')
          try:
              collectionData = client.send_request('/collections', auth=False)
          except ServerError as e:
              print('%s' % e)
          except AppError as e:
              print('%s: %s' % (e.name, e.message))

          for collection in collectionData['collections']:
              print('%s %s' % (collection['name'], collection['version'])

   BaseClient Constructor
       In our example we only provide BaseClient() with the URL fragment it uses as the  base  of
       all requests.  There are several more optional parameters that can be helpful.

       If  you need to make an authenticated request you can specify the username and password to
       use when you construct your BaseClient using the username and password keyword  arguments.
       If  you do not use these, authenticated requests will try to connect via a cookie that was
       saved from previous runs of BaseClient.  If that fails as well, BaseClient will  throw  an
       Exception which you can catch in order to prompt for a new username and password:

          from fedora.client import BaseClient, AuthError
          import getpass
          MAX_RETRIES = 5
          client = BaseClient('https://admin.fedoraproject.org/pkgdb',
                  username='foo', password='bar')
          # Note this is simplistic.  It only prompts once for another password.
          # Your application may want to loop through this several times.
          while (count < MAX_RETRIES):
              try:
                  collectionData = client.send_request('/collections', auth=True)
              except AuthError as e:
                  client.password = getpass.getpass('Retype password for %s: ' % username)
              else:
                  # data retrieved or we had an error unrelated to username/password
                  break
              count = count + 1

       WARNING:
          Note  that although you can set the username and password as shown above you do have to
          be careful in cases  where  your  application  is  multithreaded  or  simply  processes
          requests  for  more  than  one  user with the same BaseClient.  In those cases, you can
          accidentally overwrite the username and password between two requests.  To avoid  this,
          make  sure  you  instantiate  a  separate BaseClient for every thread of control or for
          every request you handle or use ProxyClient instead.

       The useragent parameter is useful for identifying in log files that your script is calling
       the  server  rather  than  another.   The default value is Fedora BaseClient/VERSION where
       VERSION is the version of the BaseClient module.  If you want to override this  just  give
       another string to this:

          client = BaseClient('https://admin.fedoraproject.org/pkgdb',
                  useragent='Package Database Client/1.0')

       The  debug  parameter  turns on a little extra output when running the program.  Set it to
       true if you're having trouble and want to figure out  what  is  happening  inside  of  the
       BaseClient code.

   send_request()
       send_request() is what does the heavy lifting of making a request of the server, receiving
       the  reply,  and  turning  that  into  a  python  dictionary.    The   usage   is   pretty
       straightforward.

       The  first argument to send_request() is method. It contains the name of the method on the
       server.  It also has any of the positional parameters that the method expects (extra  path
       information interpreted by the server for those building non-TurboGears applications).

       The  auth keyword argument is a boolean.  If True, the session cookie for the user is sent
       to the server.  If this fails, the username and password are  sent.   If  that  fails,  an
       Exception is raised that you can handle in your code.

       req_params  contains  a  dictionary of additional keyword arguments for the server method.
       These would be the names and values returned via a form  if  it  was  a  CGI.   Note  that
       parameters  passed  as  extra  path  information  should  be  added to the method argument
       instead.

       An example:

          import BaseClient
          client = BaseClient('https://admin.fedoraproject.org/pkgdb/')
          client.send_request('/package/name/python-fedora', auth=False,
                  req_params={'collectionVersion': '9', 'collectionName': 'Fedora'})

       In this particular example, knowing how the  server  works,  /packages/name/  defines  the
       method  that  the  server is going to invoke.  python-fedora is a positional parameter for
       the name of the package we're looking up.  auth=False means that we'll try to look at this
       method  without  having  to  authenticate.   The  req_params  sends two additional keyword
       arguments: collectionName which specifies whether to filter on a single distro or  include
       Fedora,  Fedora  EPEL,  Fedora OLPC, and Red Hat Linux in the output and collectionVersion
       which specifies which version of the distribution to output for.

       The URL constructed by BaseClient to the server could be expressed as[#]_:

          https://admin.fedoraproject.org/pkgdb/package/name/python-fedora/?collectionName=Fedora&collectionVersion=9

       In previous releases of  python-fedora,  there  would  be  one  further  query  parameter:
       tg_format=json.   That  parameter  instructed the server to return the information as JSON
       data instead of HTML.  Although this is usually still supported in the server,  BaseClient
       has  deprecated this method.  Servers should be configured  to use an Accept header to get
       this information instead.  See the JSON output section of the Fedora Service documentation
       for more information about the server side.

   Subclassing
       Building  a  client using subclassing builds on the information you've already seen inside
       of BaseClient.  You might want to use this if you want  to  provide  a  module  for  third
       parties  to  access a particular Fedora Service.  A subclass can provide a set of standard
       methods for calling the server instead of forcing the user to remember the  URLs  used  to
       access the server directly.

       Here's  an  example  that  turns  the previous calls into the basis of a python API to the
       Fedora Package Database:

          import getpass
          import sys
          from fedora.client import BaseClient, AuthError

          class MyClient(BaseClient):
              def __init__(self, baseURL='https://admin.fedoraproject.org/pkgdb',
                      username=None, password=None,
                      useragent='Package Database Client/1.0', debug=None):
                  super(BaseClient, self).__init__(baseURL, username, password,
                          useragent, debug)

              def collection_list(self):
                  '''Return a list of collections.'''
                  return client.send_request('/collection')

              def package_owners(self, package, collectionName=None,
                      collectionVersion=None):
                  '''Return a mapping of release to owner for this package.'''
                  pkgData = client.send_request('/packages/name/%s' % (package),
                          {'collectionName': collectionName,
                          'collectionVersion': collectionVersion})
                  ownerMap = {}
                  for listing in pkgData['packageListings']:
                      ownerMap['-'.join(listing['collection']['name'],
                              listing['collection']['version'])] = \
                              listing['owneruser']
                  return ownerMap

       A few things to note:

       1. In our constructor we list a default baseURL and useragent.  This  is  usually  a  good
          idea  as  we know the URL of the Fedora Service we're connecting to and we want to know
          that people are using our specific API.

       2. Sometimes we'll want methods that are  thin  shells  around  the  server  methods  like
          collection_list().   Other  times we'll want to do more post processing to get specific
          results as package_owners() does.  Both types of methods are  valid  if  they  fit  the
          needs  of  your  API.  If you find yourself writing more of the latter, though, you may
          want to consider getting a new method implemented in the server that can return results
          more  appropriate to your needs as it could save processing on the server and bandwidth
          downloading the data to get information that more closely matches what you need.

       See pydoc fedora.accounts.fas2 for a module that implements a standard client API for  the
       Fedora Account System

   Handling Errors
       BaseClient  will  throw  a  variety  of errors that can be caught to tell you what kind of
       error was generated.

   Exceptions
       FedoraServiceError
              The base of all exceptions raised by BaseClient.  If your code needs to  catch  any
              of the listed errors then you can catch that to do so.

       ServerError
              Raised  if  there's  a problem communicating with the service.  For instance, if we
              receive an HTML response instead of JSON.

       AuthError
              If something happens during authentication, like an invalid usernsme  or  password,
              AuthError  will  be  raised.   You  can  catch  this  to  prompt the user for a new
              usernsme.

       AppError
              If there is a server side error when processing a request, the Fedora  Service  can
              alert  the  client  of  this  by setting certain flags in the response.  BaseClient
              will see these flags and raise an AppError.  The name of the error will  be  stored
              in AppError's name field.  The error's message will be stored in message.

   Example
       Here's an example of the exceptions in action:

          from fedora.client import ServerError, AuthError, AppError, BaseClient
          import getpass
          MAXRETRIES = 5

          client = BaseClient('https://admin.fedoraproject.org/pkgdb')
          for retry in range(0, MAXRETRIES):
              try:
                  collectionData = client.send_request('/collections', auth=True)
              except AuthError as e:
                  from six.moves import input
                  client.username = input('Username: ').strip()
                  client.password = getpass.getpass('Password: ')
                  continue
              except ServerError as e:
                  print('Error talking to the server: %s' % e)
                  break
              except AppError as e:
                  print('The server issued the following exception: %s: %s' % (
                        e.name, e.message))

              for collection in collectionData['collections']:
                  print('%s %s' % (collection[0]['name'], collection[0]['version']))

   OpenIdBaseClient
       Applications  that  use OpenId to authenticate are not able to use the standard BaseClient
       because the pattern of authenticating is very different.  We've written a separate  client
       object called OpenIdBaseClient to do this.

EXISTING SERVICES

       There  are many Services in Fedora.  Many of these have an interface that we can query and
       get back information as JSON data.  There is documentation here about  both  the  services
       and the client modules that can access them.

   Fedora Account System
       FAS is the Fedora Account System.  It holds the account data for all of our contributors.

       class    fedora.client.AccountSystem(base_url='https://admin.fedoraproject.org/accounts/',
       *args, **kwargs)
              An object for querying the Fedora Account System.

              The Account System object provides a python API for talking to the  Fedora  Account
              System.   It abstracts the http requests, cookie handling, and other details so you
              can concentrate on the methods that are important to your program.

              WARNING:
                 If your code is trying to use the AccountSystem object to  connect  to  fas  for
                 multiple users you probably want to use FasProxyClient instead.  If your code is
                 trying to reuse a single  instance  of  AccountSystem  for  multiple  users  you
                 definitely  want  to  use  FasProxyClient instead.  Using AccountSystem in these
                 cases may result in a user being logged in as a different user.   (This  may  be
                 the  case  even  if  you instantiate a new AccountSystem object for each user if
                 :attr:cache_session: is True since that creates a file on the file  system  that
                 can end up loading session credentials for the wrong person.

              Changed  in  version  0.3.26: Added gravatar_url() that returns a url to a gravatar
              for a user.

              Changed in version 0.3.33: Renamed gravatar_url() to avatar_url().

              avatar_url(username, size=64, default=None, lookup_email=True, service=None)
                     Returns a URL to an avatar for a given username.

                     Avatars are drawn from third party services.

                     Parametersusername -- FAS username to construct a avatar url for

                            • size -- size of  the  avatar.   Allowed  sizes  are  32,  64,  140.
                              Default: 64

                            • default  --  If  the  service  does not have a avatar image for the
                              email address, this url is returned instead.  Default:  the  fedora
                              logo at the specified size.

                            • lookup_email  --  If  true, use the email from FAS for gravatar.com
                              lookups, otherwise just append @fedoraproject.org to the  username.
                              For libravatar.org lookups, this is ignored.  The openid identifier
                              of the user is used instead.  Note that gravatar.com  lookups  will
                              be  much  slower  if lookup_email is set to True since we'd have to
                              make a query against FAS itself.

                            • service  --  One   of   'libravatar'   or   'gravatar'.    Default:
                              'libravatar'.

                     Raises ValueError  -- if the size parameter is not allowed or if the service
                            is not one of 'libravatar' or 'gravatar'

                     Return type
                            str

                     Returns
                            url of a avatar for the user

                     If that user has no avatar entry, instruct the remote service to redirect us
                     to the Fedora logo.

                     If  that  user has no email attribute, then make a fake request to the third
                     party service.

                     New in version 0.3.26.

              create_group(name, display_name, owner, group_type, invite_only=0, needs_sponsor=0,
              user_can_remove=1, prerequisite='', joinmsg='', apply_rules='None')
                     Creates a FAS group.

                     Parametersname -- The short group name (alphanumeric only).

                            • display_name -- A longer version of the group's name.

                            • owner -- The username of the FAS account which owns the new group.

                            • group_type  --  The  kind  of  group  being  created. Current valid
                              options are git, svn, hg, shell, and tracking.

                            • invite_only -- Users must be invited to the group, they cannot join
                              on their own.

                            • needs_sponsor -- Users must be sponsored into the group.

                            • user_can_remove -- Users can remove themselves from the group.

                            • prerequisite  --  Users  must be in the given group (string) before
                              they can join the new group.

                            • joinmsg -- A message shown to users when they apply to the group.

                            • apply_rules -- Rules for applying to  the  group,  shown  to  users
                              before they apply.

                     Return type
                            munch.Munch

                     Returns
                            A Munch containing information about the group that was created.

                     New in version 0.3.29.

              get_config(username, application, attribute)
                     Return the config entry for the key values.

                     Parametersusername -- Username of the person

                            • application -- Application for which the config is set

                            • attribute -- Attribute key to lookup

                     Raises AppError -- if the server returns an exception

                     Returns
                            The unicode string that describes the value.  If no entry matched the
                            username, application, and attribute then None is returned.

              get_configs_like(username, application, pattern='*')
                     Return the config entries that match the keys and the pattern.

                     Note: authentication on the server will prevent anyone but the user or a fas
                     admin from viewing or changing their configs.

                     Parametersusername -- Username of the person

                            • application -- Application for which the config is set

                            • pattern  --  A  pattern  to select values for.  This accepts * as a
                              wildcard character. Default='*'

                     Raises AppError -- if the server returns an exception

                     Returns
                            A dict mapping attribute to value.

              gravatar_url(*args, **kwargs)
                     Deprecated - Use avatar_url.

                     New in version 0.3.26.

              group_by_id(group_id)
                     Returns a group object based on its id

              group_by_name(groupname)
                     Returns a group object based on its name

              group_data(force_refresh=None)
                     Return administrators/sponsors/users and group type for all groups

                     Parameters
                            force_refresh -- If true, the returned data will be queried from  the
                            database, as opposed to memcached.

                     Raises AppError -- if the query failed on the server

                     Returns
                            A  dict mapping group names to the group type and the user IDs of the
                            administrator, sponsors, and users of the group.

                     New in version 0.3.8.

              group_members(groupname)
                     Return a list of people approved for a group.

                     This method returns a list of people who are in the  requested  group.   The
                     people are all approved in the group.  Unapproved people are not shown.  The
                     format of data is:

                        \[{'username': 'person1', 'role_type': 'user'},
                        \{'username': 'person2', 'role_type': 'sponsor'}]

                     role_type can be one of 'user', 'sponsor', or 'administrator'.

                     New in version 0.3.2.

                     Changed in version 0.3.21: Return a Bunch instead of a DictContainer

              insecure
                     If this attribute is set to True, do not check server  certificates  against
                     their  CA's.   This  means  that man-in-the-middle attacks are possible. You
                     might turn this option on for testing against a local version  of  a  server
                     with a self-signed certificate but it should be off in production.

              people_by_groupname(groupname)
                     Return a list of persons for the given groupname.

                     Parameters
                            groupname -- Name of the group to look up

                     Returns
                            A  list  of  person objects from the group.  If the group contains no
                            entries, then an empty list is returned.

              people_by_id()
                     Deprecated Use people_by_key() instead.

                     Returns a dict  relating  user  IDs  to  human_name,  email,  username,  and
                     bugzilla email

                     Changed in version 0.3.21: Return a Bunch instead of a DictContainer

              people_by_key(key='username', search='*', fields=None)
                     Return a dict of people

                     For example:

                     >>> ret_val = FASCLIENT.people_by_key(
                     ...     key='email', search='toshio*', fields=['id'])
                     >>> ret_val.keys()
                     a.badger@[...].com
                     a.badger+test1@[...].com
                     a.badger+test2@[...].com
                     >>> ret_val.values()
                     100068
                     102023
                     102434

                     Parameterskey  -- Key used to organize the returned dictionary.  Valid values
                              are 'id', 'username', or 'email'.  Default is 'username'.

                            • search -- Pattern to match usernames against.  Defaults to the  '*'
                              wildcard which matches everyone.

                            • fields --

                              Limit  the data returned to a specific list of fields.  The default
                              is to retrieve all fields.  Valid fields are:

                                 • affiliation

                                 • alias_enabled

                                 • bugzilla_email

                                 • certificate_serial

                                 • comments

                                 • country_code

                                 • creation

                                 • email

                                 • emailtoken

                                 • facsimile

                                 • gpg_keyid

                                 • group_roles

                                 • human_name

                                 • id

                                 • internal_comments

                                 • ircnick

                                 • last_seen

                                 • latitude

                                 • locale

                                 • longitude

                                 • memberships

                                 • old_password

                                 • password

                                 • password_changed

                                 • passwordtoken

                                 • postal_address

                                 • privacy

                                 • roles

                                 • ssh_key

                                 • status

                                 • status_change

                                 • telephone

                                 • timezone

                                 • unverified_email

                                 • username

                              Note that for most users who access this data, many of these fields
                              will be set to None due to security or privacy settings.

                     Returns
                            a dict relating the key value to the fields.

                     Changed in version 0.3.21: Return a Bunch instead of a DictContainer

                     Changed  in version 0.3.26: Fixed to return a list with both people who have
                     signed the CLA and have not

              people_query(constraints=None, columns=None)
                     Returns a list of dicts representing database rows

                     Parametersconstraints -- A dictionary specifying WHERE constraints on columns

                            • columns -- A list of columns to be selected in the query

                     Raises AppError -- if the query failed on the server  (most  likely  because
                            the server was given a bad query)

                     Returns
                            A  list of dicts representing database rows (the keys of the dict are
                            the columns requested)

                     New in version 0.3.12.1.

              person_by_id(person_id)
                     Returns a person object based on its id

              person_by_username(username)
                     Returns a person object based on its username

              proxy = None

              set_config(username, application, attribute, value)
                     Set a config entry in FAS for the user.

                     Note: authentication on the server will prevent anyone but the user or a fas
                     admin from viewing or changing their configs.

                     Parametersusername -- Username of the person

                            • application -- Application for which the config is set

                            • attribute -- The name of the config key that we're setting

                            • value -- The value to set this to

                     Raises AppError -- if the server returns an exception

              user_data()
                     Return user data for all users in FAS

                     Note:  If the user is not authorized to see password hashes, '*' is returned
                     for the hash.

                     Raises AppError -- if the query failed on the server

                     Returns
                            A dict mapping user IDs to a username, password hash, SSH public key,
                            email address, and status.

                     New in version 0.3.8.

              user_gencert()
                     Generate a cert for a user

              user_id()
                     Returns a dict relating user IDs to usernames

              verify_password(username, password)
                     Return whether the username and password pair are valid.

                     Parametersusername -- username to try authenticating

                            • password -- password for the user

                     Returns
                            True if the username/password are valid.  False otherwise.

   Threadsafe Account System Access
       It  is  not safe to use a single instance of the AccountSystem object in multiple threads.
       This is because instance variables are used to hold some  connection-specific  information
       (for  instance,  the  user  who  is  logging  in).   For  this reason, we also provide the
       fedora.client.FasProxyClient object.

       This is especially handy when writing authn and authz adaptors that talk  to  fas  from  a
       multithreaded webserver.

       class   fedora.client.FasProxyClient(base_url='https://admin.fedoraproject.org/accounts/',
       *args, **kwargs)
              A threadsafe client to the Fedora Account System.

              get_user_info(auth_params)
                     Retrieve information about a logged in user.

                     Parameters
                            auth_params -- Auth information for a particular user.  For instance,
                            this  can  be  a  username/password  pair  or a session_id.  Refer to
                            fedora.client.proxyclient.ProxyClient.send_request()  for   all   the
                            legal values for this.

                     Returns
                            a tuple of session_id and information about the user.

                     Raises AuthError -- if the auth_params do not give access

              group_list(auth_params)
                     Retrieve a list of groups

                     Parameters
                            auth_params -- Auth information for a particular user.  For instance,
                            this can be a username/password  pair  or  a  session_id.   Refer  to
                            fedora.client.proxyclient.ProxyClient.send_request()   for   all  the
                            legal values for this.

                     Returns
                            a tuple of session_id  and  information  about  groups.   The  groups
                            information is in two fields:

                            groups contains information about each group

                            memberships
                                   contains  information  about  which users are members of which
                                   groups

                     Raises AuthError -- if the auth_params do not give access

              login(username, password)
                     Login to the Account System

                     Parametersusername -- username to send to FAS

                            • password -- Password to verify the username with

                     Returns
                            a tuple of the session id FAS has associated with the  user  and  the
                            user's  account  information.  This is similar to what is returned by
                            fedora.client.proxyclient.ProxyClient.get_user_info()

                     Raises AuthError -- if the username and password do not work

              logout(session_id)
                     Logout of the Account System

                     Parameters
                            session_id -- a FAS session_id to remove from FAS

              person_by_id(person_id, auth_params)
                     Retrieve information about a particular person

                     Parameters
                            auth_params -- Auth information for a particular user.  For instance,
                            this  can  be  a  username/password  pair  or a session_id.  Refer to
                            fedora.client.proxyclient.ProxyClient.send_request()  for   all   the
                            legal values for this.

                     Returns
                            a tuple of session_id and information about the user.

                     RaisesAppError -- if the server returns an exception

                            • AuthError -- if the auth_params do not give access

              refresh_session(session_id)
                     Try to refresh a session_id to prevent it from timing out

                     Parameters
                            session_id -- FAS session_id to refresh

                     Returns
                            session_id that FAS has set now

              verify_password(username, password)
                     Return whether the username and password pair are valid.

                     Parametersusername -- username to try authenticating

                            • password -- password for the user

                     Returns
                            True if the username/password are valid.  False otherwise.

              verify_session(session_id)
                     Verify that a session is active.

                     Parameters
                            session_id  --  session_id  to  verify is currently associated with a
                            logged in user

                     Returns
                            True if the session_id is valid.  False otherwise.

   Bodhi, the Update Server
       Bodhi is used to push updates from the build system to the download repositories.  It lets
       packagers send packages to the testing repository or to the update repository.

       pythyon-fedora  currently  supports  both  the  old  Bodhi1  interface  and the new Bodhi2
       interface.  By using fedora.client.BodhiCLient, the correct one should be returned to  you
       depending on what is running live on Fedora Infrastructure servers.

FEDORA SERVICES

       Authors
              Toshio Kuratomi Luke Macken

       Date   02 February 2009

       For Version
              0.3.x

       In  the  loosest  sense,  a  Fedora  Service  is  a  web  application that sends data that
       BaseClient is able to understand.  This document defines things  that  a  web  application
       must currently do for BaseClient to understand it.

   TurboGears and fedora.tg
       Functions and classes to help build a Fedora Service.

       All  current Fedora Services are written in TurboGears.  Examples in this document will be
       for that framework.  However, other frameworks can be used to write a Service if they  can
       correctly create the data that BaseClient needs.

       A  Fedora  Service  differs  from  other web applications in that certain URLs for the web
       application are an API layer that the Service can send and  receive  JSON  data  from  for
       BaseClient  to  interpret.   This imposes certain constraints on what data can be sent and
       what data can be received from those URLs.  The fedora.tg module contains  functions  that
       help you write code that communicated well with BaseClient.

       The TurboGears framework separates an application into model, view, and controller layers.
       The model is typically a database and holds the raw data that the application needs.   The
       view  formats  the  data before output.  The controller makes decisions about what data to
       retrieve from the model and which view to pass it onto.  The code that you'll  most  often
       need  to  use  from  fedora.tg operates on the controller layer but there's also code that
       works on the model and view behind the scenes.

   Controllers
       The controller is the code that processes an http request.   It  validates  and  processes
       requests and parameters sent by the user, gets data from the model to satisfy the request,
       and then passes it onto a view layer to be returned to the user.  fedora.tg.utils contains
       several helpful functions for working with controllers.

   URLs as API
       In  TurboGears and most web frameworks, a URL is a kind of API for accessing the data your
       web app provides.  This data can be made available in multiple formats.  TurboGears allows
       you  to use one URL to serve multiple formats by specifying a query parameter or a special
       header.

   Selecting JSON Output
       A URL in TurboGears can serve double duty by returning multiple formats depending  on  how
       it is called.  In most cases, the URL will return HTML or XHTML by default.  By adding the
       query parameter, tg_format=json you can  switch  from  returning  the  default  format  to
       returning  JSON  data.   You need to add an @expose(allow_json=True) decorator [1] to your
       controller method to tell TurboGears that this controller should return JSON data:

          @expose(allow_json=True)
          @expose(template='my.templates.amplifypage')
          def amplify(self, data):

       allow_json=True is a shortcut for this:

          @expose("json", content_type="text/javascript",
                  as_format="json", accept_format="text/javascript")

       That means that the controller method will  use  the  json  template  (uses  TurboJson  to
       marshal  the  returned data to JSON) to return data of type text/javascript when either of
       these conditions is met:  a query param of tg_format=json or  an  Accept:  text/javascript
       header is sent.

       BaseClient  in  python-fedora  0.1.x and 0.2.x use the query parameter method of selecting
       JSON output.  BaseClient 0.2.99.6 and 0.3.x use both  the  header  method  and  the  query
       parameter  since  the  argument was made that the header method is friendlier to other web
       frameworks.  0.4 intends to use the header alone.  If you use allow_json=True this  change
       shouldn't matter.  If you specify the @expose("json") decorator only accept_format is set.
       So it is advisable to include both as_format and accept_format in  your  decorator.   Note
       that  this is a limitation of TurboGears <= 1.0.4.4.  If your application is only going to
       run on TurboGears > 1.0.4.4 you should be able to use a plain @expose("json") [2].

       [1]  http://docs.turbogears.org/1.0/ExposeDecorator#same-method-different-template

       [2]  http://trac.turbogears.org/ticket/1459#comment:4

   Why Two Formats from a Single URL?
       When designing your URLs you might wonder why you'd want to return JSON and  HTML  from  a
       single controller method instead of having two separate controller methods.  For instance,
       separating   the   URLs    into    their    own    namespaces    might    seem    logical:
       /app/json/get_user/USERNAME  as opposed to /app/user/USERNAME.  Doing things with two URLs
       as opposed to one has both benefits and drawbacks.

   Benefits of One Method Handling Multiple Formats
       • Usually less code as there's only one controller method

       • When a user sees a page that they want to get data from, they can get it as JSON instead
         of screen scraping.

       • Forces  the  application  designer to think more about the API that is being provided to
         the users instead of just the needs of the web page they are creating.

       • Makes it easier to see what data an application will  need  to  implement  an  alternate
         interface since you can simply look at the template code to see what variables are being
         used on a particular page.

   Benefits of Multiple Methods for Each Format
       • Avoids special casing for error handlers (See below)

       • Separates URLs that you intend users to grab JSON data from URLs where you only want  to
         display HTML.

       • Allows  the  URLs that support JSON to concentrate on trimming the size of the data sent
         while URLs that only return HTML can return whole objects.

       • Organization can be better if you don't have to include all of the pages that  may  only
         be useful for user interface elements.

       Personal use has found that allowing JSON requests on one controller method works well for
       cases where you want the user to get data and for traditional form based user interaction.
       AJAX requests have been better served via dedicated methods.

   Return Values
       The  toplevel of the return values should be a dict.  This is the natural return value for
       TurboGears applications.

   Marshaling
       All data should be encoded in JSON before being returned.  This is normally taken care  of
       automatically  by TurboGears and simplejson.  If you are returning non-builtin objects you
       may have to define an __json__() method.

   Unicode
       simplejson (and probably other JSON libraries) will take care of encoding Unicode  strings
       to  JSON  so  be sure that you are passing Unicode strings around rather than encoded byte
       strings.

   Error Handling
       In python, error conditions are handled by raising an exception.   However,  an  exception
       object  will not propagate automatically through a return from the server.  Instead we set
       several special variables in the returned data to inform BaseClient of any errors.

       At present, when BaseClient receives an error it raises an exception of its own  with  the
       exception information from the server inside.  Raising the same exception as the server is
       being investigated but may pose security risks so hasn't yet been implemented.

   exc
       All URLs which return JSON data  should  set  the  exc  variable  when  the  method  fails
       unexpectedly (a database call failed, a place where you would normally raise an exception,
       or where you'd redirect to an error page if a user was viewing the HTML version of the web
       app).   exc should be set to the name of an exception and tg_flash set to the message that
       would normally be given to the exception's  constructor.   If  the  return  is  a  success
       (expected  values  are being returned from the method or a value was updated successfully)
       exc may either be unset or set to None.

   tg_flash
       When viewing the HTML web app, tg_flash can be set with a message to display to  the  user
       either  on the next page load or via an AJAX handler.  When used in conjunction with JSON,
       exc=EXCEPTIONNAME, and BaseClient, tg_flash should be set to an  error  message  that  the
       client can use to identify what went wrong or display to the user.  It's equivalent to the
       message you would normally give when raising an exception.

   Authentication Errors
       Errors in authentication  are  a  special  case.   Instead  of  returning  an  error  with
       exc='AuthError' set, the server should return with response.status = 403.  BaseClient will
       see the 403 and raise an AuthError.

       This is the signal for the client to ask the user  for  new  credentials  (usually  a  new
       username and password).

       NOTE:
          Upstream  TurboGears  has  switched  to  sending  a  401  for  authentication problems.
          However, their use of 401 is  against  the  http  specification  (It  doesn't  set  the
          'WWW-Authentication'  header)  and  it  causes  problems for konqueror and webkit based
          browsers so we probably will not be switching.

   Performing Different Actions when Returning JSON
       So far we've run across  three  features  of  TurboGears  that  provide  value  to  a  web
       application  but don't work when returning JSON data.  We provide a function that can code
       around this.  fedora.tg.utils.request_format() will return the format  that  the  page  is
       being  returned  as.   Code  can  use this to check whether JSON output is expected and do
       something different based on it:

          output = {'tg_flash': 'An Error Occurred'}
          if fedora.tg.utils.request_format() == 'json':
              output['exc'] = 'ServerError'
          else:
              output['tg_template'] = 'my.templates.error'
          return output

       In this example, we return an error through our "exception" mechanism if we are  returning
       JSON and return an error page by resetting the template if not.

   Redirects
       Redirects do not play well with JSON [3] because TurboGears is unable to turn the function
       returned from the redirect into a dictionary that can be turned into JSON.

       Redirects are commonly used to express errors.  This is actually  better  expressed  using
       tg_template  because  that method leaves the URL intact.  That allows the end user to look
       for spelling mistakes in their URL.  If you need to use a redirect,  the  same  recipe  as
       above will allow you to split your code paths.

       [3]  Last checked in TurboGears 1.0.4

   tg_template
       Setting what template is returned to a user by setting tg_template in the return dict (for
       instance, to display an error page without changing the URL) is a perfectly valid  way  to
       use  TurboGears.   Unfortunately,  since JSON is simply another template in TurboGears you
       have to be sure not to interfere with the generation of JSON  data.   You  need  to  check
       whether  JSON  was  requested  using  fedora.tg.utils.request_format()  and  only return a
       different template if that's not the case.  The recipe above shows how to do this.

   Validators
       Validators are slightly different than the issues we've encountered  so  far.   Validators
       are  used  to  check  and convert parameters sent to a controller method so that only good
       data is dealt with in the controller method itself.  The problem is that when a  validator
       detects  a  parameter that is invalid, it performs a special internal redirect to a method
       that is its error_handler.  We can't intercept this redirect because  it  happens  in  the
       decorators  before  our  method  is invoked.  So we have to deal with the aftermath of the
       redirect in the error_handler method:

          class NotNumberValidator(turbogears.validators.FancyValidator):
              messages = {'Number': 'Numbers are not allowed'}

              def to_python(self, value, state=None):
                  try:
                      number = turbogears.validators.Number(value.strip())
                  except:
                      return value
                  raise validators.Invalid(self.message('Number', state), value,
                          state)

          class AmplifyForm(turbogears.widgets.Form):
              template = my.templates.amplifyform
              submit_text = 'Enter word to amplify'
              fields = [
                      turbogears.widgets.TextField(name='data',
                              validator=NotNumberValidator())
                      ]

          amplify_form = AmplifyForm()

          class mycontroller(RootController):

              @expose(template='my.templates.errorpage', allow_json=True)
              def no_numbers(self, data):
                  errors = fedora.tg.utils.jsonify_validation_errors()
                  if errors:
                      return errors
                  # Construct a dict to return the data error message as HTML via
                  # the errorpage template
                  pass

              @validate(form=amplify_form)
              @error_handler('no_numbers')
              @expose(template='my.templates.amplifypage', allow_json=True)
              def amplify(self, data):
                  return dict(data=data.upper())

       When a user hits amplify()'s URL, the validator checks whether data is a  number.   If  it
       is,  it  redirects  to the error_handler, no_numbers().  no_numbers() will normally return
       HTML which is fine if we're simply hitting amplify() from a web browser.  If we're hitting
       it  from a BaseClient app, however, we need it to return JSON data instead.  To do that we
       use jsonify_validation_errors() which checks whether there  was  a  validation  error  and
       whether  we  need to return JSON data.  If both of those are true, it returns a dictionary
       with the validation errors.   This  dictionary  is  appropriate  for  returning  from  the
       controller method in response to a JSON request.

       WARNING:
          When  defining  @error_handler() order of decorators can be important.  The short story
          is to always make @validate() and @error_handler() the first decorators of your method.
          The  longer  version  is  that  this is known to cause errors with the json request not
          being honored or skipping identity checks when the method is its own error handler.

   Expected Methods
       Certain controller methods are necessary in order for BaseClient to properly talk to  your
       service.   TurboGears  can  quickstart  an  application template for you that sets most of
       these variables correctly:

          $ tg-admin quickstart -i -s -p my my
          # edit my/my/controllers.py

   login()
       You need to have a  login()  method  in  your  application's  root.   This  method  allows
       BaseClient to authenticate against your Service:

               @expose(template="my.templates.login")
          +    @expose(allow_json=True)
               def login(self, forward_url=None, previous_url=None, \*args, \**kw):

                   if not identity.current.anonymous \
                       and identity.was_login_attempted() \
                       and not identity.get_identity_errors():
          +            # User is logged in
          +            if 'json' == fedora.tg.utils.request_format():
          +                return dict(user=identity.current.user)
          +            if not forward_url:
          +                forward_url = turbogears.url('/')
                       raise redirect(forward_url)

   For non-TurboGears Implementors
       If  you are implementing a server in a non-TurboGears framework, note that one of the ways
       to reach the login() method  is  through  special  parameters  parsed  by  the  TurboGears
       framework.   BaseClient  uses  these  parameters  instead  of  invoking the login() method
       directly as it saves a round trip when authenticating to the server.  It will be necessary
       for you to implement handling of these parameters (passed via POST) on your application as
       well.

       The parameters are: user_name, password, and login.  When these three parameters are  sent
       to  the  server,  the  server  authenticates the user and records their information before
       deciding what information to return to them from the URL.

   logout()
       The logout() method is similar to login().  It also needs to be modified to  allow  people
       to connect to it via JSON:

          -    @expose()
          +    @expose(allow_json=True)
               def logout(self):
                   identity.current.logout()
          +        if 'json' in fedora.tg.utils.request_format():
          +            return dict()
                   raise redirect("/")

   CSRF Protection
       For  an  overview  of  CSRF  and  how to protect TurboGears 1 based services, look at this
       document.

   CSRF Protection
       Authors
              Toshio Kuratomi

       Date   21 February 2009

       For Version
              0.3.x

       CSRF, Cross-Site Request Forgery is a technique where a malicious website can gain  access
       to  a  Fedora Service by hijacking a currently open session in a user's web browser.  This
       technique affects identification via SSL Certificates, cookies, or anything else that  the
       browser  sends  to the server automatically when a request to that server is made.  It can
       take place over both GET and POST.  GET requests just need to hit a vulnerable URL.   POST
       requests require JavaScript to construct the form that is sent to the vulnerable server.

       NOTE:
          If  you  just want to implement this in Fedora-Services, skip to the Summary of Changes
          Per App section

   How CSRF Works
       1. A vulnerable web service allows users to change things  on  their  site  using  just  a
          cookie for authentication and submission of a form or by hitting a URL with an img tag.

       2. A  malicious  website  is  crafted that looks harmless but has JavaScript or an img tag
          that sends a request to the web service with the form data or just hits the  vulnerable
          URL.

       3. The  user goes somewhere that people who are frequently logged into the site are at and
          posts something innocuous that gets people to  click  on  the  link  to  the  malicious
          website.

       4. When  a  user  who  is logged into the vulnerable website clicks on the link, their web
          browser loads the page.  It sees the img tag and contacts  the  vulnerable  website  to
          request the listed URL sending the user's authentication cookie automatically.

       5. The  vulnerable  server  performs  the  action  that the URL requires as the user whose
          cookies were sent and the damage is done... typically  without  the  user  knowing  any
          better until much later.

   How to Prevent It
   Theory
       In order to remove this problem we need to have a shared secret between the user's browser
       and the web site that is only available via the http  request-response.   This  secret  is
       required  in  order  for any actions to be performed on the site.  Because the Same Origin
       Policy prevents the malicious website from reading the web page itself,  a  shared  secret
       passed  in  this manner will prevent the malicious site from performing any actions.  Note
       that this secret cannot be transferred from the user's browser to the server via a  cookie
       because  this  is  something  that  the  browser  does automatically.  It can, however, be
       transferred from the server to the browser via  a  cookie  because  the  browser  prevents
       scripts from other domains from reading the cookies.

   Practice
       The  strategy  we've adopted is sometimes called double submit.  Every time we POST a form
       or make a GET request that requires us to be authenticated we must  also  submit  a  token
       consisting  of  a hash of the tg-visit to show the server that we were able to read either
       the cookie or the response from a previous request.  We store the token value in a GET  or
       POST  parameter  named  _csrf_token.   If  the  server  receives  the tg-visit without the
       _csrf_token parameter, the server renders the user anonymous until the user clicks another
       link.

       NOTE:
          We hash the tg-visit session to make the token because we sometimes send the token as a
          parameter in GET requests so it will show up in the servers http logs.

   Verifying the Token
       The jsonfasprovider1 does the work of verifying that _csrf_token has been set and that  it
       is  a  valid  hash of the tg-visit token belonging to the user.  The sequence of events to
       verify a user's identity follows this outline:

       1. If username and password given

          1. Verify with the identity provider that the username and password match

              1. [YES] authenticate the user

              2. [NO] user is anonymous.

       2. if tg-visit cookie present

          1. if session_id from tg-visit is in the db  and  not  expired  and  (sha1sum(tg-visit)
             matches _csrf_token given as a (POST variable or GET variable)

              1. [YES] authenticate the user

              2. [NO]  Take  user  to  login  page  that  just requires the user to click a link.
                 Clicking the link shows that it's not just JavaScript in the browser  attempting
                 to  load  the  page but an actual user.  Once the link is clicked, the user will
                 have a _csrf_token.  If  the  link  is  not  clicked  the  user  is  treated  as
                 anonymous.

          2. Verify via SSL Certificate

              1. SSL  Certificate  is not revoked and  able to retrieve info for the username and
                 (sha1sum(tg-visit) matches _csrf_token given as a POST variable or GET variable)

                 1. [YES] authenticate the user

                 2. [NO] Take user to login page that just requires the user  to  click  a  link.
                    Clicking  the  link  shows  that  it's  not  just  JavaScript  in the browser
                    attempting to load the page but an actual user.  Once the  link  is  clicked,
                    the  user  will  have  a _csrf_token.  If the link is not clicked the user is
                    treated as anonymous.

       This work should mostly happen behind the scenes so the application  programmer  does  not
       need to worry about this.

       SEE ALSO:
          The jsonfasprovider1 documentation has more information on methods that are provided by
          the identity provider in case you do need to tell what the authentication token is  and
          whether it is missing.

   Getting the Token into the Page
       Embedding  the  CSRF  token  into the URLs that the user can click on is the other half of
       this problem.  fedora.tg.utils provides two functions to make this easier.

       This function does everything tg.url() does in the templates.  In addition it  makes  sure
       that _csrf_token is appended to the URL.

       This  function  sets  config  values  to  allow _csrf_token to be passed to any URL on the
       server and makes turbogears.url() point to our url() function.   Once  this  is  run,  the
       tg.url()  function  you  use in the templates will make any links that use with it contain
       the CSRF protecting token.

   Intra-Application Links
       We support single sign-on among the web applications we've written for Fedora.   In  order
       for  this  to  continue  working  with  this  CSRF  protection  scheme  we have to add the
       _csrf_token parameter to links between Fedora-Services.  Linking  from  the  PackageDB  to
       Bodhi,  for  instance,  needs  to  have the hash appended to the URL for Bodhi.  Our url()
       function is capable of generating these by passing the full URL  into  the  function  like
       this:

          <a href="${tg.url('https://admin.fedoraproject.org/updates')}">Bodhi</a>

       NOTE:
          You   probably   already  use  tg.url()  for  links  within  you  web  app  to  support
          server.webpath.  Adding tg.url() to external links is new.  You  will  likely  have  to
          update your application's templates to call url() on these URLs.

   Logging In
       Each app's login() controller method and templates need to be modified in several ways.

   Templates
       For  the templates, python-fedora provides a set of standard templates that can be used to
       add the token.

       Genshi version of templates to make adding certain Fedora widgets easier.

   fedora.tg.templates.genshi.login.html
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.10.

       Include this using::
              <xi:include href="${tg.fedora_template('login.html')}" />

       fedora.tg.templates.genshi.login.html.loginform([message])

       message
              Any text or elements contained by the <loginform> tag will be shown as a message to
              the user.  This is generally used to show status of the last login attempt ("Please
              provide your credentials", "Supplied credentials were not correct", etc)

       A match template for the main login form.  This is a CSRF token-aware login form that will
       prompt  for  username and password when no session identity is present and ask the user to
       click a link if they merely lack a token.

       Typical usage would be:

          <loginform>${message}</loginform>

       fedora.tg.templates.genshi.login.html.logintoolitem(@href=URL)

       @href  If an href attribute is present for this tag, when  a  user  is  logged  in,  their
              username or display_name will be a link to the URL.

       A match template to add an entry to a toolbar.  The entry will contain the user's username
       and a logout button if the user is logged in, a verify login button  if  the  user  has  a
       session  cookie but not a CSRF token, or a login button if the user doesn't have a session
       cookie.

       Typical usage looks like this:

          <ul class="toolbar" id="#main-toolbar">
            <logintoolitem href="${tg.url('/users/info')}" />
          </ul>

   fedora.tg.templates.genshi.jsglobals.html
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.10.

       Include this using::
              <xi:include href="${tg.fedora_template('jsglobals.html')}" />

       fedora.tg.templates.genshi.jsglobals.html.jsglobals()

       A match template to add global variables to a page.  Typically, you'd include this in your
       master.html  template  and  let it be added to every other page from there.  This adds the
       following variables in the fedora namespace for other scripts to access:

          fedora.baseurl
                 URL fragment to prepend to any  calls  to  the  application.   In  a  TurboGears
                 application,   this   is   the   scheme,  host,  and  server.webpath.   Example:
                 https://admin.fedoraproject.org/pkgdb/.  This may be a relative link.

          fedora.identity.anonymous
                 If true, there will be no other variables in the fedora.identity namespace.   If
                 false, these variables are defined:

          fedora.identity.userid
                 Numeric, unique identifier for the user

          fedora.identity.username
                 Publically visible unique identifier for the user

          fedora.identity.display_name
                 Common human name for the user

          fedora.identity.token
                 csrf token for this user's session to be added to urls that query the server.

       Typical usage would be:

          <jsglobals />

       Using  the <loginform> template will give you a login form that automatically does several
       things for you.

       1. The forward_url and previous_url parameters that are passed  in  hidden  form  elements
          will be run through tg.url() in order to get the _csrf_token added.

       2. The  page  will  allow  "Click  through  validation"  of  a user when they have a valid
          tg-visit but do not have a _csrf_token.

       Here's a complete login.html from the pkgdb to show what this could look like:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml"
                xmlns:py="http://genshi.edgewall.org/"
                xmlns:xi="http://www.w3.org/2001/XInclude">
            <xi:include href="master.html" />
            <xi:include href="${tg.fedora_template('login.html')}" />

            <head>
              <meta content="text/html; charset=UTF-8"
              http-equiv="content-type" py:replace="''"/>
              <title>Login to the PackageDB</title>
            </head>

            <body>
              <loginform>${message}</loginform>
            </body>
          </html>

       You should notice that this looks like a typical genshi template in your project with  two
       new    features.     The    <loginform>    tag    in    the   body   that's   defined   in
       fedora.tg.templates.genshi is  used  in  the  body  to  pull  in  the  login  formand  the
       <xi:include>   of   login.html   uses  tg.fedora_template()  to  load  the  template  from
       python-fedora.  This function resides in fedora.tg.utils and is added to the  tg  template
       variable when enable_csrf() is called at startup.  It does the following:

       The  second  match template in login.html is to help you modify the login and logout links
       that appear at the top of a typical application's page.  This is an optional  change  that
       lets  the  links  display  a  click-through  login link in addition to the usual login and
       logout.   To  use  this,  you  would  follow  the  example  to  add  a  toolbar  with  the
       <logintoolitem>  into  your  master  template.  Here's some snippets from a master.html to
       illustrate:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml"
                xmlns:py="http://genshi.edgewall.org/"
                xmlns:xi="http://www.w3.org/2001/XInclude">

          [...]
            <body py:match="body" py:attrs="select('@*')">
          [...]
              <div id="head">
                <h1><a href="http://fedoraproject.org/index.html">Fedora</a></h1>
                <ul class="toolbar" id="#main-toolbar">
                  <logintoolitem href="${tg.url('/users/info')}" />
                </ul>
              </div>
          [...]
            </body>
            <xi:include href="${tg.fedora_template('login.html')}" />
            <xi:include href="${tg.fedora_template('jsglobals.html')}" />
          </html>

       WARNING:
          Notice that the <xi:include> of  login.html  happens  after  the  <body>  tag?   It  is
          important  to  do  that  because the <body> tag in master.html is a match template just
          like <logintoolitem>.  In genshi, the order in which match  templates  are  defined  is
          significant.

       If  you need to look at these templates to modify them yourself (perhaps to port them to a
       different templating language) you can find them in  fedora/tg/templates/genshi/login.html
       in the source tarball.

   Controllers
       Calling  Fedora-Services  from  JavaScript  poses one further problem.  Sometimes the user
       will not have a current CSRF token and will need to log in.  When  this  is  done  with  a
       username  and password there's no problem because the username and password are sufficient
       to prove the user is in control of the browser.  However, when using an  SSL  Certificate,
       we  need  the  browser  to  log  in and then use the new CSRF token to show the user is in
       control.  Since JavaScript calls are most likely going to request the information as JSON,
       we  need  to  provide  the token in the dict returned from login().  You can either modify
       your login() method to do that or use the one provided in fedora.tg.controllers.login().

       NOTE:
          Fedora Services do not currently use certificate authentication but doing it would  not
          take  much  code.   Working out the security ramifications within Infrastructure is the
          main sticking point to turning this on.

       NOTE:
          The Fedora Account System has a slightly different login() method.  This is because  it
          has  to  handle account expiration, mandatory password resets, and other things tied to
          the status of an account.  Other Fedora Services rely on FAS  to  do  this  instead  of
          having to handle it themselves.

   AJAX
       Making  JavaScript  calls  requires  that  we  can get the token and add it to the URLs we
       request.  Since JavaScript doesn't have a standard library of crypto functions we  provide
       the  token  by  setting it via a template so we do not have to calculate it on the client.
       This has the added bonus of propagating a  correct  token  even  if  we  change  the  hash
       function later.  Making use of the token can then be done in ad hoc JavaScript code but is
       better handled via a dedicated JavaScript method like the fedora.dojo.BaseClient.

   Template
       WARNING:
          Just like login.html, the <xi:include> tag needs to come after  the  <body>  tag  since
          they're both match templates.

   JavaScript
       The  fedora.dojo.BaseClient class has been modified to send and update the csrf token that
       is provided by fedora.identity.token.  It is highly recommended that you use this  library
       or  another  like  it to make all calls to the server.  This keeps you from having to deal
       with adding the CSRF token to every call yourself.

       Here's a small bit of sample code:

          <script type="text/javascript" src="/js/dojo/dojo.js"></script>
          <script type="text/javascript">
              dojo.require('fedora.dojo.BaseClient');
              dojo.addOnLoad(function() {
                  pkgdb = new fedora.dojo.BaseClient(fedora.baseurl, {
                      username: '', password:''});
                  pkg_data = pkgdb.start_request('/packages/name/python',
                      {req_params: {collectionName: 'Fedora',
                              collectionVersion: 'devel'}});

              });
          </script>

   Summary of Changes Per App
          • On startup, run enable_csrf().  This could be done in  a  start-APP.py  and  APP.wsgi
            scripts.  Code like this will do it:

                from turbogears import startup
                from fedora.tg.utils import enable_csrf
                startup.call_on_startup.append(enable_csrf)

          • Links  to  other  Fedora-Services  in  the templates must be run through the tg.url()
            method so that the CSRF token can be appended.

          • You must use an updated login template.  Using the one provided in  python-fedora  is
            possible by changing your login template as shown in the Templates section.

          • Optional:  update  the  master  template  that  shows the Login/Logout Link to have a
            "Verify Login" button.  You can add one to a toolbar in  your  application  following
            the instructions in the Templates section.

          • Use  an  updated  identity  provider  from  python-fedora.   At  this  time, you need
            python-fedora 0.3.10 or later which has a  jsonfasprovider2  and  jsonfasvisit2  that
            provide  CSRF protection.  The original jsonfasprovider1 is provided for applications
            that have not yet started using enable_csrf() so you have to make this change in your
            configuration file (APPNAME/config/app.cfg)

          • Get  the  CSRF  token into your forms and URLs.  The recommended way to do this is to
            use tg.url() in  your  forms  for  URLs  that  are  local  to  the  app  or  are  for
            Fedora-Services.

          • Update   your   login()   method   to   make   sure   you're  setting  forward_url  =
            request.path_info rather than request.path.  One easy way to do this is  to  use  the
            login() and logout() as documented in Controllers

          • Add  the  token  and other identity information so JavaScript can get at it.  Use the
            jsglobals template to accomplish this.

       This one still needs to be implemented

              • AJAX calls need to be enhanced to append the CSRF token to  the  data.   This  is
                best  done  using  a JavaScript function for this like the fedora.dojo.BaseClient
                library.

   Using SABase
       fedora.tg.json contains several functions that help to  convert  SQLAlchemy  objects  into
       JSON.   For  the  most  part,  these  do their work behind the scenes.  The SABase object,
       however, is one that you might need to take an active role in using.

       When you return an SQLAlchemy object in a controller to a template, the template  is  able
       to access any of the relations mapped to it.  So, instead of having to construct a list of
       people records from a table and the the list of groups that each of them are  in  you  can
       pass  in the list of people and let your template reference the relation properties to get
       the groups.  This is extremely convenient for templates but has  a  negative  effect  when
       returning JSON. Namely, the default methods for marshaling SQLAlchemy objects to JSON only
       return the attributes of the object, not the relations that are linked to it.  So you  can
       easily  run into a situation where someone querying the JSON data for a page will not have
       all the information that a template has access to.

       SABase fixes this by allowing you to specify relations that your SQLAlchemy backed objects
       should marshal as JSON data.

       Further information on SABase can be found in the API documentation:

          pydoc fedora.tg.json

   Example
       SABase is a base class that you can use when defining objects in your project's model.  So
       the first step is defining the classes in your model to inherit from SABase:

          from fedora.tg.json import SABase
          from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
          from turbogears.database import metadata, mapper

          class Person(SABase):
              pass
          PersonTable = Table('person', metadata
              Column('name', String, primary_key=True),
              )

          class Address(SABase):
              pass
          AddressTable = Table (
              Column('id', Integer, primary_key=True),
              Column('street', string),
              Column('person_id', Integer, ForeignKey('person.name')
              )

          mapper(PersonTable, Person)
          mapper(AddressTable, Address, properties = {
              person: relation(Person, backref = 'addresses'),
          })

       The next step is to tell SABase which properties should be copied (this allows you to omit
       large trees of objects when you only need the data from a few of them):

          @expose('my.templates.about_me')
          @expose(allow_json=True)
          def my_info(self):
              person = Person.query.filter_by(name='Myself').one()
              person.jsonProps = {'Person': ['addresses']}
              return dict(myself=person}

       Now,  when  someone  requests  JSON  data  from my_info, they should get back a record for
       person that includes a property addresses.  Addresses will be a list  of  address  records
       associated with the person.

   How it Works
       SABase  adds  a special __json__() method to the class.  By default, this method returns a
       dict with all of the attributes that are backed by fields in the database.

       Adding entries to jsonProps adds the values for those properties to the returned  dict  as
       well.   If  you  need to override the __json__() method in your class you probably want to
       call SABase's __json__() unless you know that neither you nor any future  subclasses  will
       need it.

   Using __json__()
       Sometimes  you need to return an object that isn't a basic python type (list, tuple, dict,
       number. string, etc).  When that occurs, simplejson won't know how  to  marshal  the  data
       into  JSON  until  you  write own method to transform the values.  If this method is named
       __json__(), TurboGears will automatically perform  the  conversion  when  you  return  the
       object.

       Example:

          class MyObject(object):
              def _init__(self, number):
                  self.someNumber = number
                  self.cached = None

              def _calc_data(self):
                  if not self.cached:
                      self.cached = self.someNumber * 2
                  return self.cached

              twiceData = property(_calc_data)

              def __json__(self):
                  return {'someNumber': self.someNumber, 'twiceData': self.twiceData}

       In  this  class,  you  have  a  variable  and a property.  If you were to return it from a
       controller method without defining the __json__() method, TurboGears  would  give  you  an
       error  that  it  was  unable  to adapt the object to JSON.  The JSON method transforms the
       object into a dict with sensibly named values  for  the  variable  and  property  so  that
       simplejson  is  able to marshal the data to JSON.  Note that you will often have to choose
       between space (more data takes more bandwidth to deliver to the end user) and completeness
       (you  need  to  return enough data so the client isn't looking for another method that can
       complete its needs) when returning data.

AUTHENTICATION TO FAS

       The Fedora-Account-System has a JSON interface that we make use of to  authenticate  users
       in  our web apps.  Currently, there are two modes of operation.  Some web apps have single
       sign-on capability  with  FAS.   These  are  the  TurboGears  applications  that  use  the
       jsonfasprovider.   Other  apps  do  not  have single sign-on but they do connect to FAS to
       verify the username and password so changing the password in FAS changes it everywhere.

   TurboGears Identity Provider 2
       An identity provider with CSRF protection.

       This will install as a TurboGears identity plugin.  To use it, set the following  in  your
       APPNAME/config/app.cfg file:

          identity.provider='jsonfas2'
          visit.manager='jsonfas2'

       SEE ALSO:
          CSRF-Protection

   Turbogears Identity Provider 1
       These methods are deprecated because they do not provide the CSRF protection of TurboGears
       Identity Provider 2.  Please use that identity provider instead.

   Django Authentication Backend
   Fedora Django Authentication Backend
       Authors
              Ignacio Vazquez-Abrams

       Date   23 Feb 2009

       For Version
              0.3.x

       The django.auth package provides an authentication backend for Django projects.

       NOTE:
          Django authentication does not provide single sign-on with other Fedora web  apps.   it
          also  does  not  provide  CSRF  protection.  Look at the way that Dango's builtin forms
          implement CSRF protection for guidance on how to protect against this sort of attack.

   fedora.django.auth
       As FAS users are authenticated they are added to FasUser. FAS groups are  added  to  Group
       both during syncdb and when a user is authenticated.

   Integrating into a Django Project
       Add the following lines to the project's settings.py:

          AUTHENTICATION_BACKENDS = (
              'fedora.django.auth.backends.FasBackend',
          )

          FAS_USERNAME = '<username>'
          FAS_PASSWORD = '<password>'
          FAS_USERAGENT = '<user agent>'
          FAS_URL = '<base URL of FAS server>'
          FAS_ADMINS = ( ... )

       FAS_USERNAME and FAS_PASSWORD are used to retrieve group information during syncdb as well
       as to retrieve users via the authentication backend. They should be set to a low-privilege
       account that can read group and user information.

       FAS_USERAGENT is the string used to identify yourself to the FAS server.

       FAS_URL is the base URL of the FAS server to authenticate against.

       FAS_ADMINS  is  a  tuple of usernames that you want to have superuser rights in the Django
       project.

       Add fedora.django.auth.middleware.FasMiddleware to the MIDDLEWARE_CLASSES  tuple,  between
       django.contrib.sessions.middleware.SessionMiddleware                                   and
       django.contrib.auth.middleware.AuthenticationMiddleware.

       Additionally, set FAS_GENERICEMAIL to False in order to use the email address specified in
       FAS instead of <username>``@fedoraproject.org``.

       Add fedora.django.auth to INSTALLED_APPS.

       Finally, run python manage.py syncdb to add the models for the added app to the database.

       WARNING:
          The  User.first_name  and User.last_name attributes are always empty since FAS does not
          have any equivalents. The name read-only property results in a round trip  to  the  FAS
          server.

   Flask Auth Plugin
   FAS Flask Auth Plugin
       Authors
              Toshio Kuratomi, Ian Weller

       Date   29 October 2012

       For Version
              0.3.x

       The  Fedora-Account-System  has a JSON interface that we make use of to authenticate users
       in our web apps.  For our Flask applications we have an identity provider that has  single
       sign-on  with  our  TurboGears  1  and  2  applications.  It does not protect against CSRF
       attacks in the identity layer.  The flask-wtf forms package  should  be  used  to  provide
       that.

   Configuration
       The  FAS  auth  plugin  has several config values that can be used to control how the auth
       plugin functions.  You can set these in your application's config file.

       FAS_BASE_URL
              Set this to the URL of the FAS server you are authenticating against.   Default  is
              "https://admin.fedoraproject.org/accounts/"

       FAS_USER_AGENT
              User agent string to be used when connecting to FAS.  You can set this to something
              specific to your application to aid in debugging a connection to the FAS server  as
              it will show up in the FAS server's logs.  Default is "Flask-FAS/0.3"

       FAS_CHECK_CERT
              When  set, this will check the SSL Certificate for the FAS server to make sure that
              it is who it claims to be.  This is useful to set to False when testing  against  a
              local FAS server but should always be set to True in production.  Default: True

       FAS_COOKIE_NAME
              The  name of the cookie used to store the session id across the Fedora Applications
              that support single sign-on.  Default: "tg-visit"

       FAS_FLASK_COOKIE_REQUIRES_HTTPS
              When this is set to True, the session cookie will only be returned  to  the  server
              via  ssl (https).  If you connect to the server via plain http, the cookie will not
              be sent.  This prevents sniffing of the cookie contents.  This may be set to  False
              when  testing  your  application  but  should  always be set to True in production.
              Default is True.

   Sample Application
       The  following  is  a  sample,  minimal  flask  application  that   uses   fas_flask   for
       authentication:

          #!/usr/bin/python -tt
          # Flask-FAS - A Flask extension for authorizing users with FAS
          # Primary maintainer: Ian Weller <ianweller@fedoraproject.org>
          #
          # Copyright (c) 2012, Red Hat, Inc.
          #
          # Redistribution and use in source and binary forms, with or without
          # modification, are permitted provided that the following conditions are met:
          #
          # * Redistributions of source code must retain the above copyright notice, this
          # list of conditions and the following disclaimer.
          # * Redistributions in binary form must reproduce the above copyright notice,
          # this list of conditions and the following disclaimer in the documentation
          # and/or other materials provided with the distribution.
          # * Neither the name of the Red Hat, Inc. nor the names of its contributors may
          # be used to endorse or promote products derived from this software without
          # specific prior written permission.
          #
          # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
          # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
          # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
          # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
          # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
          # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
          # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
          # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
          # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
          # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

          # This is a sample application. In addition to using Flask-FAS, it uses
          # Flask-WTF (WTForms) to handle the login form. Use of Flask-WTF is highly
          # recommended because of its CSRF checking.

          import flask
          from flask.ext import wtf
          from flask.ext.fas import FAS, fas_login_required

          # Set up Flask application
          app = flask.Flask(__name__)
          # Set up FAS extension
          fas = FAS(app)

          # Application configuration
          # SECRET_KEY is necessary to CSRF in WTForms.  It needs to be secret to
          # make the csrf tokens unguessable but if you have multiple servers behind
          # a load balancer, the key needs to be the same on each.
          app.config['SECRET_KEY'] = 'change me!'
          # Other configuration options for Flask-FAS:
          #     FAS_BASE_URL: the base URL for the accounts system
          #         (default https://admin.fedoraproject.org/accounts/)
          #     FAS_CHECK_CERT: check the SSL certificate of FAS (default True)
          #     FAS_FLASK_COOKIE_REQUIRES_HTTPS: send the 'secure' option with
          #          the login cookie (default True)
          # You should use these options' defaults for production applications!
          app.config['FAS_BASE_URL'] = 'https://fakefas.fedoraproject.org/accounts/'
          app.config['FAS_CHECK_CERT'] = False
          app.config['FAS_FLASK_COOKIE_REQUIRES_HTTPS'] = False

          # A basic login form
          class LoginForm(wtf.Form):
              username = wtf.TextField('Username', [wtf.validators.Required()])
              password = wtf.PasswordField('Password', [wtf.validators.Required()])

          # Inline templates keep this test application all in one file. Don't do this in
          # a real application. Please.
          TEMPLATE_START = """
          <h1>Flask-FAS test app</h1>
          {% if g.fas_user %}
              <p>Hello, {{ g.fas_user.username }} &mdash;
              <a href="{{ url_for("logout") }}">Log out</a>
          {% else %}
              <p>You are not logged in &mdash;
              <a href="{{ url_for("auth_login", next=request.url) + '' }}">Log in</a>
          {% endif %}
          &mdash; <a href="{{ url_for("index") }}">Main page</a></p>
          """

          @app.route('/')
          def index():
              data = TEMPLATE_START
              data += '<p><a href="%s">Check if you are cla+1</a></p>' % \
                      flask.url_for('claplusone')
              data += '<p><a href="%s">See a secret message (requires login)</a></p>' % \
                      flask.url_for('secret')
              return flask.render_template_string(data)

          @app.route('/login', methods=['GET', 'POST'])
          def auth_login():
              # Your application should probably do some checking to make sure the URL
              # given in the next request argument is sane. (For example, having next set
              # to the login page will cause a redirect loop.) Some more information:
              # http://flask.pocoo.org/snippets/62/
              if 'next' in flask.request.args:
                  next_url = flask.request.args['next']
              else:
                  next_url = flask.url_for('index')
              # If user is already logged in, return them to where they were last
              if flask.g.fas_user:
                  return flask.redirect(next_url)
              # Init login form
              form = LoginForm()
              # Init template
              data = TEMPLATE_START
              data += ('<p>Log into the <a href="{{ config.FAS_BASE_URL }}">'
                       'Fedora Accounts System</a>:')
              # If this is POST, process the form
              if form.validate_on_submit():
                  if fas.login(form.username.data, form.password.data):
                      # Login successful, return
                      return flask.redirect(next_url)
                  else:
                      # Login unsuccessful
                      data += '<p style="color:red">Invalid login</p>'
              data += """
          <form action="" method="POST">
          {% for field in [form.username, form.password] %}
              <p>{{ field.label }}: {{ field|safe }}</p>
              {% if field.errors %}
                  <ul style="color:red">
                  {% for error in field.errors %}
                      <li>{{ error }}</li>
                  {% endfor %}
                  </ul>
              {% endif %}
          {% endfor %}
          <input type="submit" value="Log in">
          {{ form.csrf_token }}
          </form>"""
              return flask.render_template_string(data, form=form)

          @app.route('/logout')
          def logout():
              if flask.g.fas_user:
                  fas.logout()
              return flask.redirect(flask.url_for('index'))

          # This demonstrates the use of the fas_login_required decorator. The
          # secret message can only be viewed by those who are logged in.
          @app.route('/secret')
          @fas_login_required
          def secret():
              data = TEMPLATE_START + '<p>Be sure to drink your Ovaltine</p>'
              return flask.render_template_string(data)

          # This demonstrates checking for group membership inside of a function.
          # The flask_fas adapter also provides a cla_plus_one_required decorator that
          # can restrict a url so that you can only access it from an account that has
          # cla +1.
          @app.route('/claplusone')
          def claplusone():
              data = TEMPLATE_START
              if not flask.g.fas_user:
                  # Not logged in
                  return flask.render_template_string(data +
                          '<p>You must log in to check your cla +1 status</p>')
              non_cla_groups = [x.name for x in flask.g.fas_user.approved_memberships
                                if x.group_type != 'cla']
              if len(non_cla_groups) > 0:
                  data += '<p>Your account is cla+1.</p>'
              else:
                  data += '<p>Your account is <em>not</em> cla+1.</p>'
              return flask.render_template_string(data)

          if __name__ == '__main__':
              app.run(debug=True)

   Flask FAS OpenId Auth Plugin
       The  flask_openid  provider  is an alternative to the flask_fas auth plugin.  It leverages
       our FAS-OpenID server to do authn and authz (group  memberships).   Note  that  not  every
       feature  is  available  with a generic OpenID provider -- the plugin depends on the OpenID
       provider having certain extensions in order to provide more than basic OpenID auth.

       • Any compliant OpenID server should allow you to use the basic authn features  of  OpenID
         OpenID authentication core: http://openid.net/specs/openid-authentication-2_0.html

       • Retrieving simple information about the user such as username, human name, email is done
         with sreg:  http://openid.net/specs/openid-simple-registration-extension-1_0.html  which
         is an extension supported by many providers.

       • Advanced  security  features such as requiring a user to re-login to the OpenID provider
         or specifying that the user login with a hardware token  requires  the  PAPE  extension:
         http://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html

       • To     get     groups     information,     the     provider     must    implement    the
         https://dev.launchpad.net/OpenIDTeams extension.

         • We  have  extended  the  teams  extension  so  you  can  request  a   team   name   of
           _FAS_ALL_GROUPS_  to  retrieve  all  the  groups that a user belongs to.  Without this
           addition to the teams extension you will need to manually configure which  groups  you
           are interested in knowing about.  See the documentation for how to do so.

       • Retrieving  information  about  whether a user has signed a CLA (For Fedora, this is the
         Fedora Project Contributor Agreement).  http://fedoraproject.org/specs/open_id/cla

       If the provider you use does not support one of these extensions, the plugin should  still
       work  but  naturally,  it  will return empty values for the information that the extension
       would have provided.

   FAS Flask OpenID Auth Plugin
       Authors
              Patrick Uiterwjk

       Date   18 February 2013

       For Version
              0.3.x

       The Fedora-Account-System has a OpenID provider that applications can use to  authenticate
       users  in web apps. For our Flask applications we have an identity provider that uses this
       OpenID service to authenticate users.  It is almost completely compatible  with  flask_fas
       except  that  it does not use the username/password provided by the client application (it
       is silently ignored). It can be configured to use any OpenID authentication  service  that
       implements the OpenID Teams Extension, Simple Registration Extension and CLA Extension.

   Configuration
       The  FAS  OpenID auth plugin has several config values that can be used to control how the
       auth plugin functions.  You can set these in your application's config file.

       FAS_OPENID_ENDPOINT
              Set this to the OpenID endpoint url you are authenticating against.  Default is  "‐
              http://id.fedoraproject.org/"

       FAS_CHECK_CERT
              When  set, this will check the SSL Certificate for the FAS server to make sure that
              it is who it claims to be.  This is useful to set to False when testing  against  a
              local FAS server but should always be set to True in production.  Default: True

   Sample Application
       The   following   is   a  sample,  minimal  flask  application  that  uses  fas_flask  for
       authentication:

          #!/usr/bin/python -tt
          # Flask-FAS-OpenID - A Flask extension for authorizing users with OpenID
          # Primary maintainer: Patrick Uiterwijk <puiterwijk@fedoraproject.org>
          #
          # Copyright (c) 2012-2013, Red Hat, Inc., Patrick Uiterwijk
          #
          # Redistribution and use in source and binary forms, with or without
          # modification, are permitted provided that the following conditions are met:
          #
          # * Redistributions of source code must retain the above copyright notice, this
          # list of conditions and the following disclaimer.
          # * Redistributions in binary form must reproduce the above copyright notice,
          # this list of conditions and the following disclaimer in the documentation
          # and/or other materials provided with the distribution.
          # * Neither the name of the Red Hat, Inc. nor the names of its contributors may
          # be used to endorse or promote products derived from this software without
          # specific prior written permission.
          #
          # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
          # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
          # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
          # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
          # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
          # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
          # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
          # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
          # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
          # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

          # This is a sample application.

          import flask
          from flask_fas_openid import fas_login_required, cla_plus_one_required, FAS

          # Set up Flask application
          app = flask.Flask(__name__)
          # Set up FAS extension
          fas = FAS(app)

          # Application configuration
          # SECRET_KEY is necessary for the Flask session system.  It needs to be secret to
          # make the sessions secret but if you have multiple servers behind
          # a load balancer, the key needs to be the same on each.
          app.config['SECRET_KEY'] = 'change me!'
          # Other configuration options for Flask-FAS-OpenID:
          #     FAS_OPENID_ENDPOINT: the OpenID endpoint URL
          #         (default http://id.fedoraproject.org/)
          #     FAS_CHECK_CERT: check the SSL certificate of FAS (default True)
          # You should use these options' defaults for production applications!
          app.config['FAS_OPENID_ENDPOINT'] = 'http://id.fedoraproject.org/'
          app.config['FAS_CHECK_CERT'] = True

          # Inline templates keep this test application all in one file. Don't do this in
          # a real application. Please.
          TEMPLATE_START = """
          <h1>Flask-FAS-OpenID test app</h1>
          {% if g.fas_user %}
              <p>Hello, {{ g.fas_user.username }} &mdash;
              <a href="{{ url_for("logout") }}">Log out</a>
          {% else %}
              <p>You are not logged in &mdash;
              <a href="{{ url_for("auth_login", next=request.url) + '' }}">Log in</a>
          {% endif %}
          &mdash; <a href="{{ url_for("index") }}">Main page</a></p>
          """

          @app.route('/')
          def index():
              data = TEMPLATE_START
              data += '<p><a href="%s">Check if you are cla+1</a></p>' % \
                      flask.url_for('claplusone')
              data += '<p><a href="%s">See a secret message (requires login)</a></p>' % \
                      flask.url_for('secret')
              return flask.render_template_string(data)

          @app.route('/login', methods=['GET', 'POST'])
          def auth_login():
              # Your application should probably do some checking to make sure the URL
              # given in the next request argument is sane. (For example, having next set
              # to the login page will cause a redirect loop.) Some more information:
              # http://flask.pocoo.org/snippets/62/
              if 'next' in flask.request.args:
                  next_url = flask.request.args['next']
              else:
                  next_url = flask.url_for('index')
              # If user is already logged in, return them to where they were last
              if flask.g.fas_user:
                  return flask.redirect(next_url)
              return fas.login(return_url=next_url)

          @app.route('/logout')
          def logout():
              if flask.g.fas_user:
                  fas.logout()
              return flask.redirect(flask.url_for('index'))

          # This demonstrates the use of the fas_login_required decorator. The
          # secret message can only be viewed by those who are logged in.
          @app.route('/secret')
          @fas_login_required
          def secret():
              data = TEMPLATE_START + '<p>Be sure to drink your Ovaltine</p>'
              return flask.render_template_string(data)

          # This demonstrates checking for group membership inside of a function.
          # The flask_fas adapter also provides a cla_plus_one_required decorator that
          # can restrict a url so that you can only access it from an account that has
          # cla +1.
          @app.route('/claplusone')
          @cla_plus_one_required
          def claplusone():
              data = TEMPLATE_START
              data += '<p>Your account is cla+1.</p>'
              return flask.render_template_string(data)

          if __name__ == '__main__':
              app.run(debug=True)

   FAS Who Plugin for TurboGears2
   FASWho Plugin
       Authors
              Luke Macken Toshio Kuratomi

       Date   3 September 2011

       This plugin provides authentication to the Fedora Account System using the repoze.who WSGI
       middleware.   It  is  designed  for  use  with  TurboGears2  but  it  may be used with any
       repoze.who using application.  Like jsonfas2, faswho has builtin  CSRF  protection.   This
       protection  is  implemented  as  a  second  piece of middleware and may be used with other
       repoze.who authentication schemes.

   Authenticating against FAS with TurboGears2
       Setting up authentication against FAS in TurboGears2 is very easy.  It requires one change
       to  be made to app/config/app_cfg.py.  This change will take care of registering faswho as
       the  authentication  provider,  enabling  CSRF  protection,  switching  tg.url()  to   use
       fedora.ta2g.utils.url() instead, and allowing the _csrf_token parameter to be given to any
       URL.

   Using CSRF middleware with other Auth Methods
       This section needs to be made clearer so that apps like mirrormanager can be ported to use
       this.

   Templates
       The  fedora.tg2.utils  module  contains  some templates to help you write CSRF aware login
       forms and buttons.  You can use the fedora_template() function to integrate them into your
       templates:

       The  templates  themselves come in two flavors.  One set for use with mako and one set for
       use with genshi.

   Mako
       Mako version of templates to make adding certain Fedora widgets easier.

   fedora.tg2.templates.mako.login.mak
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.25.

       Include this using:

          <%namespace name="fedora" file="${context['fedora_template']('login.mak')}" />

       fedora.tg2.templates.mako.login.mak.loginform(message='')

       kwarg message
              Any text or elements contained by the <loginform> tag will be shown as a message to
              the user.  This is generally used to show status of the last login attempt ("Please
              provide your credentials", "Supplied credentials were not correct", etc)

       A function for generating the main login form.  This is a CSRF token-aware login form that
       will prompt for username and password when no session identity is present and ask the user
       to click a link if they merely lack a token.

       Typical usage, given the above import of the login.mak template would be:

          ${fedora.loginform()}

       fedora.tg2.templates.mako.login.mak.logintoolitem(href=None)

       kwarg href
              If an href is given, when a user is logged in, their username or display_name  will
              be a link to the URL.

       This  function creates an entry into a toolbar for logging into a web app.  The entry will
       contain the user's username and a logout button if the user is logged in, a  verify  login
       button  if  the  user  has a session cookie but not a CSRF token, or a login button if the
       user doesn't have a session cookie.

       Typical usage looks like this:

          <ul class="toolbar" id="#main-toolbar">
            ${fedora.logintoolitem(href=tg.url('/users/info'))}
          </ul>

   fedora.tg2.templates.mako.jsglobals.mak
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.25.

       Include this using:

          <%namespace name="jsglobals" file="${context['fedora_template']('jsglobals.mak')}" />

       fedora.tg2.templates.mako.jsglobals.mak.jsglobals()

       A function to add global variables to a page.   Typically,  you'd  include  this  in  your
       master.mak template and let the javascript variables defined there propagate to every page
       on your site (since they all should inherit from master.mak).   This  adds  the  following
       variables in the fedora namespace for other scripts to access:

          fedora.baseurl
                 URL  fragment  to  prepend  to  any  calls  to the application.  In a TurboGears
                 application,  this  is  the  scheme,   host,   and   server.webpath.    Example:
                 https://admin.fedoraproject.org/pkgdb/.  This may be a relative link.

          fedora.identity.anonymous
                 If  true, there will be no other variables in the fedora.identity namespace.  If
                 false, these variables are defined:

          fedora.identity.userid
                 Numeric, unique identifier for the user

          fedora.identity.username
                 Publically visible unique identifier for the user

          fedora.identity.display_name
                 Common human name for the user

          fedora.identity.token
                 csrf token for this user's session to be added to urls that query the server.

       Typical usage would be:

          ${jsglobals.jsglobals()}

   Genshi
       Genshi version of templates to make adding certain Fedora widgets easier.

   fedora.tg2.templates.genshi.login.html
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.26.

       Include this using::
              <xi:include href="${fedora_template('login.html', template_type='genshi')}" />

       fedora.tg2.templates.genshi.login.html.loginform([message])

       message
              Any text or elements contained by the <loginform> tag will be shown as a message to
              the user.  This is generally used to show status of the last login attempt ("Please
              provide your credentials", "Supplied credentials were not correct", etc)

       A match template for the main login form.  This is a CSRF token-aware login form that will
       prompt  for  username and password when no session identity is present and ask the user to
       click a link if they merely lack a token.

       Typical usage would be:

          <loginform>${message}</loginform>

       fedora.tg2.templates.genshi.login.html.logintoolitem(@href=URL)

       @href  If an href attribute is present for this tag, when  a  user  is  logged  in,  their
              username or display_name will be a link to the URL.

       A match template to add an entry to a toolbar.  The entry will contain the user's username
       and a logout button if the user is logged in, a verify login button  if  the  user  has  a
       session  cookie but not a CSRF token, or a login button if the user doesn't have a session
       cookie.

       Typical usage looks like this:

          <ul class="toolbar" id="#main-toolbar">
            <logintoolitem href="${tg.url('/users/info')}" />
          </ul>

   fedora.tg2.templates.genshi.jsglobals.html
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.26.

       Include this using::
              <xi:include href="${fedora_template('jsglobals.html', template_type='genshi')}" />

       fedora.tg2.templates.genshi.jsglobals.html.jsglobals()

       A match template to add global variables to a page.  Typically, you'd include this in your
       master.html  template  and  let it be added to every other page from there.  This adds the
       following variables in the fedora namespace for other scripts to access:

          fedora.baseurl
                 URL fragment to prepend to any  calls  to  the  application.   In  a  TurboGears
                 application,   this   is   the   scheme,  host,  and  server.webpath.   Example:
                 https://admin.fedoraproject.org/pkgdb/.  This may be a relative link.

          fedora.identity.anonymous
                 If true, there will be no other variables in the fedora.identity namespace.   If
                 false, these variables are defined:

          fedora.identity.userid
                 Numeric, unique identifier for the user

          fedora.identity.username
                 Publically visible unique identifier for the user

          fedora.identity.display_name
                 Common human name for the user

          fedora.identity.token
                 csrf token for this user's session to be added to urls that query the server.

       Typical usage would be:

          <jsglobals />

JAVASCRIPT

       Authors
              Toshio Kuratomi

       Date   26 February 2009

       For Version
              0.3.x

       python-fedora  currently  provides  some  JavaScript  files to make coding Fedora-Services
       easier.  In the future we may move these to their own package.

   fedora.dojo
       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       New in version 0.3.10.

       Dojo is one of several JavaScript  Toolkits.   It  aims  to  be  a  standard  library  for
       JavaScript.   The fedora.dojo module has JavaScript code that make use of Dojo to do their
       work.  It is most appropriate to use when  the  Dojo  libraries  are  being  used  as  the
       JavaScript library for the app.  However, it is well namespaced and nothing should prevent
       it from being used in other apps as well.

API DOCUMENTATION

       This API Documentation is currently a catch-all.  We're going to merge the API  docs  into
       the hand created docs as we have time to integrate them.

   Client
       fedora.client is used to interact with Fedora Services.

       Changed in version 0.3.21: Deprecate DictContainer in favor of bunch.Bunch

       Changed in version 0.3.35: Add the openid clients

       Module author: Ricky Zhou <ricky@fedoraproject.org>

       Module author: Luke Macken <lmacken@redhat.com>

       Module author: Toshio Kuratomi <tkuratom@redhat.com>

       exception fedora.client.FedoraServiceError
              Base Exception for any problem talking with the Service.

              When  the  Client gets an error talking to the server, an exception of this type is
              raised.  This can be anything in the networking layer up to an error returned  from
              the server itself.

       exception fedora.client.ServerError(url, status, msg)
              Unable to talk to the server properly.

              This  includes  network  errors and 500 response codes.  If the error was generated
              from an http response, code is the HTTP response code.  Otherwise, code will be -1.

       exception fedora.client.AuthError
              Error during authentication.  For instance, invalid password.

       exception fedora.client.AppError(name, message, extras=None)
              Error condition that the server is passing back to the client.

       exception fedora.client.FedoraClientError
              Base Exception for problems which originate within the Clients.

              This should be the  base  class  for  any  exceptions  that  the  Client  generates
              generate.   For instance, if the client performs validation before passing the data
              on to the Fedora Service.

              Problems  returned  while  talking  to  the  Services  should  be  returned  via  a
              FedoraServiceError instead.

       exception fedora.client.FASError
              FAS Error

       exception fedora.client.CLAError
              CLA Error

       exception fedora.client.BodhiClientException

       class fedora.client.DictContainer(*args, **kwargs)

   Generic Clients
   BaseClient
       class   fedora.client.BaseClient(base_url,  useragent=None,  debug=False,  insecure=False,
       username=None,   password=None,   httpauth=None,   session_cookie=None,   session_id=None,
       session_name='tg-visit', cache_session=True, retries=None, timeout=None)
              A client for interacting with web services.

              logout()
                     Logout from the server.

              send_request(method,  req_params=None,  file_params=None, auth=False, retries=None,
              timeout=None, **kwargs)
                     Make an HTTP request to a server method.

                     The given method is called with any parameters set in req_params.   If  auth
                     is True, then the request is made with an authenticated session cookie.

                     Parametersmethod  --  Method to call on the server.  It's a url fragment that
                              comes after the base_url set in __init__().

                            • req_params -- Extra parameters to send to the server.

                            • file_params -- dict of files where the key is the name of the  file
                              field  used in the remote method and the value is the local path of
                              the file to be uploaded.  If you want to pass multiple files  to  a
                              single file field, pass the paths as a list of paths.

                            • auth -- If True perform auth to the server, else do not.

                            • retries  --  if  we get an unknown or possibly transient error from
                              the server, retry this many times.   Setting  this  to  a  negative
                              number  makes it try forever.  Default to use the retries value set
                              on the instance or  in  __init__()  (which  defaults  to  zero,  no
                              retries).

                            • timeout  --  A  float describing the timeout of the connection. The
                              timeout  only  affects  the  connection  process  itself,  not  the
                              downloading  of the response body. Default to use the timeout value
                              set on the instance or in __init__() (which defaults to 120s).

                     Return type
                            Bunch

                     Returns
                            The data from the server

                     Changed  in  version  0.3.21:  *  Return  data  as  a  Bunch  instead  of  a
                     DictContainer * Add file_params to allow uploading files

                     Changed in version 0.3.33: * Added the timeout kwarg

              session_cookie
                     Deprecated, use session_id instead.

                     The  session  cookie  is saved in a file in case it is needed in consecutive
                     runs of BaseClient.

              session_id
                     The session_id.

                     The session id is saved in a file in case it is needed in  consecutive  runs
                     of BaseClient.

   ProxyClient
       class    fedora.client.ProxyClient(base_url,    useragent=None,   session_name='tg-visit',
       session_as_cookie=True, debug=False, insecure=False, retries=None, timeout=None)
              A client to a Fedora Service.  This class is optimized to proxy multiple users to a
              service.  ProxyClient is designed to be threadsafe so that code can instantiate one
              instance of the class and use it for multiple requests  for  different  users  from
              different threads.

              If  you  want  something that can manage one user's connection to a Fedora Service,
              then look into using BaseClient instead.

              This class has several  attributes.   These  may  be  changed  after  instantiation
              however,  please note that this class is intended to be threadsafe.  Changing these
              values when another thread may affect more than just the thread that you are making
              the  change in.  (For instance, changing the debug option could cause other threads
              to start logging debug messages in the middle of a method.)

              base_url
                     Initial portion of the url to contact the server.  It is highly  recommended
                     not to change this value unless you know that no other threads are accessing
                     this ProxyClient instance.

              useragent
                     Changes the useragent string that is reported to the web server.

              session_name
                     Name of the cookie that holds the authentication value.

              session_as_cookie
                     If True, then the session information is saved locally as a cookie.  This is
                     here  for  backwards  compatibility.  New code should set this to False when
                     constructing the ProxyClient.

              debug  If True, then more verbose logging is performed to aid in debugging issues.

              insecure
                     If True then the connection to the server is not checked to be sure that any
                     SSL certificate information is valid.  That means that a remote host can lie
                     about who it  is.   Useful  for  development  but  should  not  be  used  in
                     production code.

              retries
                     Setting  this  to  a  positive integer will retry failed requests to the web
                     server this many times.  Setting to a negative integer will retry forever.

              timeout

              A float describing the timeout of the connection. The timeout only

              affects the connection process itself, not the downloading of the

              response body. Defaults to 120 seconds.

              Changed in version 0.3.33: Added the timeout attribute

              debug  When True, we log extra debugging  statements.   When  False,  we  only  log
                     errors.

              log = <Logger fedora.client.proxyclient (WARNING)>

              send_request(method,     req_params=None,    auth_params=None,    file_params=None,
              retries=None, timeout=None)
                     Make an HTTP request to a server method.

                     The given method is called with any parameters set in req_params.   If  auth
                     is  True,  then  the  request  is made with an authenticated session cookie.
                     Note that path parameters should be set by adding onto the method,  not  via
                     req_params.

                     Parametersmethod  --  Method to call on the server.  It's a url fragment that
                              comes  after  the  base_url  set  in  __init__().   Note  that  any
                              parameters set as extra path information should be listed here, not
                              in req_params.

                            • req_params -- dict containing  extra  parameters  to  send  to  the
                              server

                            • auth_params --

                              dict  containing one or more means of authenticating to the server.
                              Valid entries in this dict are:

                              cookie Deprecated Use  session_id  instead.   If  both  cookie  and
                                     session_id  are  set,  only  session_id  will  be  used.   A
                                     Cookie.SimpleCookie to send  as  a  session  cookie  to  the
                                     server

                              session_id
                                     Session  id  to put in a cookie to construct an identity for
                                     the server

                              username
                                     Username to send to the server

                              password
                                     Password to use with username to send to the server

                              httpauth
                                     If set to basic then use HTTP Basic Authentication  to  send
                                     the  username  and  password  to  the  server.   This may be
                                     extended in the future to support other httpauth types  than
                                     basic.

                              Note  that  cookie  can  be  sent  alone  but if one of username or
                              password is set the other must as well.  Code can set all of  these
                              if it wants and all of them will be sent to the server.  Be careful
                              of sending cookies that do not match with the username in this case
                              as the server can decide what to do in this case.

                            • file_params  -- dict of files where the key is the name of the file
                              field used in the remote method and the value is the local path  of
                              the  file  to be uploaded.  If you want to pass multiple files to a
                              single file field, pass the paths as a list of paths.

                            • retries -- if we get an unknown or possibly  transient  error  from
                              the  server,  retry  this  many  times.  Setting this to a negative
                              number makes it try forever.  Default to use the retries value  set
                              on the instance or in __init__().

                            • timeout  --  A  float describing the timeout of the connection. The
                              timeout  only  affects  the  connection  process  itself,  not  the
                              downloading of the response body. Defaults to the timeout value set
                              on the instance or in __init__().

                     Returns
                            If ProxyClient is created with session_as_cookie=True (the  default),
                            a  tuple  of session cookie and data from the server.  If ProxyClient
                            was created with session_as_cookie=False, a tuple of  session_id  and
                            data instead.

                     Return type
                            tuple of session information and data from server

                     Changed in version 0.3.17: No longer send tg_format=json parameter.  We rely
                     solely on the Accept: application/json header now.

                     Changed  in  version  0.3.21:  *  Return  data  as  a  Bunch  instead  of  a
                     DictContainer * Add file_params to allow uploading files

                     Changed in version 0.3.33: Added the timeout kwarg

   OpenIdBaseClient
       class     fedora.client.OpenIdBaseClient(base_url,     login_url=None,     useragent=None,
       debug=False,  insecure=False,  openid_insecure=False,  username=None,  cache_session=True,
       retries=None, timeout=None, retry_backoff_factor=0)
              A client for interacting with web services relying on openid auth.

              has_cookies()

              login(username, password, otp=None)
                     Open a session for the user.

                     Log  in  the  user  with the specified username and password against the FAS
                     OpenID server.

                     Parametersusername -- the FAS username of the user that wants to log in

                            • password -- the FAS password of the user that wants to log in

                            • otp -- currently unused.  Eventually a way to send an  otp  to  the
                              API that the API can use.

              send_request(method, auth=False, verb='POST', **kwargs)
                     Make an HTTP request to a server method.

                     The  given  method is called with any parameters set in req_params.  If auth
                     is True, then the request is made with an authenticated session cookie.

                     Parametersmethod -- Method to call on the server.  It's a url  fragment  that
                              comes after the base_url set in __init__().

                            • auth -- If True perform auth to the server, else do not.

                            • req_params -- Extra parameters to send to the server.

                            • file_params  -- dict of files where the key is the name of the file
                              field used in the remote method and the value is the local path  of
                              the  file  to be uploaded.  If you want to pass multiple files to a
                              single file field, pass the paths as a list of paths.

                            • verb -- HTTP verb to use.  GET and POST  are  currently  supported.
                              POST is the default.

              session_key

       fedora.client.openidbaseclient.requires_login(func)
              Decorator function for get or post requests requiring login.

              Decorate a controller method that requires the user to be authenticated.  Example:

                 from fedora.client.openidbaseclient import requires_login

                 @requires_login
                 def rename_user(new_name):
                     user = new_name
                     # [...]

   OpenIdProxyClient
       class     fedora.client.OpenIdProxyClient(base_url,     login_url=None,    useragent=None,
       session_name='session', debug=False, insecure=False, openid_insecure=False,  retries=None,
       timeout=None)
              A client to a Fedora Service.  This class is optimized to proxy multiple users to a
              service.  OpenIdProxyClient is designed to be usable by code that creates a  single
              instance  of  this  class  and  uses  it  in  multiple  threads.  However it is not
              completely threadsafe.  See the information on setting attributes below.

              If you want something that can manage one user's connection to  a  Fedora  Service,
              then look into using OpenIdBaseClient instead.

              This  class  has  several  attributes.   These  may be changed after instantiation.
              Please note, however, that changing these values when another thread  is  utilizing
              the  same  instance  may  affect  more than just the thread that you are making the
              change in.  (For instance, changing the debug option could cause other  threads  to
              start logging debug messages in the middle of a method.)

              base_url
                     Initial  portion of the url to contact the server.  It is highly recommended
                     not to change this value unless you know that no other threads are accessing
                     this OpenIdProxyClient instance.

              useragent
                     Changes the useragent string that is reported to the web server.

              session_name
                     Name of the cookie that holds the authentication value.

              debug  If True, then more verbose logging is performed to aid in debugging issues.

              insecure
                     If True then the connection to the server is not checked to be sure that any
                     SSL certificate information is valid.  That means that a remote host can lie
                     about  who  it  is.   Useful  for  development  but  should  not  be used in
                     production code.

              retries
                     Setting this to a positive integer will retry failed  requests  to  the  web
                     server this many times.  Setting to a negative integer will retry forever.

              timeout
                     A  float  describing the timeout of the connection. The timeout only affects
                     the connection process itself, not the downloading  of  the  response  body.
                     Defaults to 120 seconds.

              debug  When  True,  we  log  extra  debugging  statements.  When False, we only log
                     errors.

              login(username, password, otp=None)
                     Open a session for the user.

                     Log in the user with the specified username and  password  against  the  FAS
                     OpenID server.

                     Parametersusername -- the FAS username of the user that wants to log in

                            • password -- the FAS password of the user that wants to log in

                            • otp  --  currently  unused.  Eventually a way to send an otp to the
                              API that the API can use.

                     Returns
                            a tuple containing both the response from the OpenID provider and the
                            session used to by this provider.

              send_request(method,      verb='POST',      req_params=None,      auth_params=None,
              file_params=None, retries=None, timeout=None, headers=None)
                     Make an HTTP request to a server method.

                     The given method is called with any parameters set in req_params.   If  auth
                     is  True,  then  the  request  is made with an authenticated session cookie.
                     Note that path parameters should be set by adding onto the method,  not  via
                     req_params.

                     Parametersmethod  --  Method to call on the server.  It's a url fragment that
                              comes  after  the  base_url  set  in  __init__().   Note  that  any
                              parameters set as extra path information should be listed here, not
                              in req_params.

                            • req_params -- dict containing  extra  parameters  to  send  to  the
                              server

                            • auth_params --

                              dict  containing one or more means of authenticating to the server.
                              Valid entries in this dict are:

                              cookie Deprecated Use  session_id  instead.   If  both  cookie  and
                                     session_id  are  set,  only  session_id  will  be  used.   A
                                     Cookie.SimpleCookie to send  as  a  session  cookie  to  the
                                     server

                              session_id
                                     Session  id  to put in a cookie to construct an identity for
                                     the server

                              username
                                     Username to send to the server

                              password
                                     Password to use with username to send to the server

                              httpauth
                                     If set to basic then use HTTP Basic Authentication  to  send
                                     the  username  and  password  to  the  server.   This may be
                                     extended in the future to support other httpauth types  than
                                     basic.

                              Note  that  cookie  can  be  sent  alone  but if one of username or
                              password is set the other must as well.  Code can set all of  these
                              if it wants and all of them will be sent to the server.  Be careful
                              of sending cookies that do not match with the username in this case
                              as the server can decide what to do in this case.

                            • file_params  -- dict of files where the key is the name of the file
                              field used in the remote method and the value is the local path  of
                              the  file  to be uploaded.  If you want to pass multiple files to a
                              single file field, pass the paths as a list of paths.

                            • retries -- if we get an unknown or possibly  transient  error  from
                              the  server,  retry  this  many  times.  Setting this to a negative
                              number makes it try forever.  Default to use the retries value  set
                              on the instance or in __init__().

                            • timeout  --  A float describing the timeout of the connection.  The
                              timeout  only  affects  the  connection  process  itself,  not  the
                              downloading of the response body. Defaults to the timeout value set
                              on the instance or in __init__().

                            • headers -- A dictionary containing specific headers to add  to  the
                              request made.

                     Returns
                            A tuple of session_id and data.

                     Return type
                            tuple of session information and data from server

   Clients for Specific Services
   Wiki
       class fedora.client.Wiki(base_url='https://fedoraproject.org/w/', *args, **kwargs)

              api_high_limits = False

              check_api_limits()
                     Checks whether you have the 'apihighlimits' right or not.

              fetch_all_revisions(start=1,  flags=True,  timestamp=True,  user=True,  size=False,
              comment=True,      content=False,      title=True,       ignore_imported_revs=True,
              ignore_wikibot=False, callback=None)
                     Fetch  data for all revisions. This could take a long time. You can start at
                     a specific revision by modifying the 'start' keyword argument.

                     To   ignore   revisions   made   by    "ImportUser"    and    "Admin"    set
                     ignore_imported_revs  to True (this is the default). To ignore edits made by
                     Wikibot set ignore_wikibot to True (False is the default).

                     Modifying the remainder of the keyword arguments will return less/more data.

              get_recent_changes(now, then, limit=500)
                     Get recent wiki changes from now until then

              login(username, password)

              print_recent_changes(days=7, show=10)

   Service
   Transforming SQLAlchemy Objects into JSON

GLOSSARY

       controller
              In MVC design, the controller is in charge of things.  It  takes  processes  events
              and  decides  what data to ask the model for, manipulates the data according to the
              information in the event, and decides which view to  send  the  results  to  to  be
              rendered.

       CSRF   Cross-site request forgery is a technique where a malicious website can gain access
              to another web site by hijaacking a currently open session that the user  has  open
              to the site.  This technique can also affect identification via SSL Certificates or
              anything else that the browser sends to the server automatically when a request  is
              made.

              SEE ALSO:
                 CSRF-Protection

       Dojo   Dojo is a JavaScript toolkit that aims to be a standard library for JavaScript.  It
              provides a small core library with useful functions and an expanded set of  scripts
              that can be added that provide widgets and other features.

              SEE ALSO:
                 http://www.dojotoolkit.org

       double submit
              A  strategy  to foil CSRF attacks.  This strategy involves sending the value of the
              authentication cookie (or something derivable only from knowing the  value  of  the
              authentication  cookie)  in  the body of the request.  Since the Same Origin Policy
              prevents a web site other than the one originating the cookie from  reading  what's
              in  the  cookie,  the  server  can  be reasonably assured that the request does not
              originate from an unknown request on another website.  Note  that  this  and  other
              anti-CSRF  measures  do  not protect against spoofing or getting a user to actively
              click on a link on an attacked website by mistake.

       flask  A simple Python web framework that we're using in parts of  Fedora  Infrastructure.
              It provides good documentation and simplicity in its design.

              SEE ALSO:
                 http://flask.pocoo.org/docs/

       JSON   JavaScript  Object  Notation  is  a  format for marshalling data.  It is based on a
              subset of JavaScript that is used to declare objects.  Compared to xml, JSON  is  a
              lightweight, easily parsed format.

              SEE ALSO:
                 Wikipedia's JSON Entry

       model  In MVC design, the layer that deals directly with the data.

       OpenID A  specification for single sign on to web services where the authentication server
              and the application seeking to have the user authenticated  do  not  need  to  have
              complete trust in each other.

              SEE ALSO:
                 http://openid.net/get-an-openid/what-is-openid/

       Same Origin Policy
              A  web  browser  security  policy  that  prevents  one website from reading: 1) the
              cookies from another website 2) the response body from another website

              SEE ALSO:
                 http://en.wikipedia.org/wiki/Same_origin_policy

       single sign-on
              A feature that allows one login to authenticate a user for  multiple  applications.
              So logging into one application will authenticate you for all the applications that
              support the same single-sign-on infrastructure.

       TurboGears
              A Python web framework that most of Fedora Infrastructure's apps are built on.

              SEE ALSO:
                 http://www.turbogears.org/

       TurboGears2
              The successor to TurboGears, TurboGears2  provides  a  very  similar  framework  to
              coders  but  has some notable differences. It is based on pylons and paste so it is
              much more tightly integrated with WSGI.  The differences with :ref`TurboGears`1 are
              largely with the organization of code and how to configure the application.

              SEE ALSO:
                 http://www.turbogears.org/

       view   In  MVC  design, the layer that takes care of formatting and rendering data for the
              consumer.  This could be displaying the data as an html page or marshalling it into
              JSON objects.

       WSGI   WSGI  is an interface between web servers and web frameworks that originated in the
              Python community.  WSGI lets different components embed each  other  even  if  they
              were originally written for different python web frameworks.

              SEE ALSO:
                 http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface

       • glossary

       • genindex

       • modindex

       • search

COPYRIGHT

       2007-2019 Red Hat, Inc.