Exemple #1
0
class ServiceTwo(Service):
    '''
    Just a second service, no comments here (almost same that ServiceOne
    '''
    typeName = translatable('Sample Service Two')
    typeType = 'SampleService2'
    typeDescription = translatable('Sample (and dummy) service ONE+ONE')
    iconFile = 'provider.png'  #: We reuse provider icon here :-)

    # Functional related data
    maxDeployed = 5
    usesCache = True
    cacheTooltip = translatable('L1 cache for dummy elements')
    usesCache_L2 = True
    cacheTooltip_L2 = translatable('L2 cache for dummy elements')

    needsManager = False
    mustAssignManually = False

    #: Types of publications. In this case, we will include a publication
    #: type for this one
    #: Note that this is a MUST if you indicate that needPublication
    publicationType = SamplePublication
    #: Types of deploys (services in cache and/or assigned to users)
    deployedType = SampleUserDeploymentTwo

    # Gui, we will use here the EditableList field
    names = gui.EditableList(label=translatable('List of names'))

    def __init__(self, environment, parent, values=None):
        '''
        We here can get a HUGE list from client.
        Right now, this is treated same as other fields, in a near
        future we will se how to handle this better
        '''
        super(ServiceTwo, self).__init__(environment, parent, values)

        # No checks here

    def getNames(self):
        '''
        For using at deployed services, really nothing
        '''
        return self.names.value
Exemple #2
0
 def initialize(self, values):
     '''
     Simply check if we have
     at least one group in the list
     '''
     
     # To avoid problems, we only check data if values are passed
     # If values are not passed in, form data will only be available after
     # unserialization, and at this point all will be default values
     # so self.groups.value will be []
     if values is not None and len(self.groups.value) < 2:
         raise auths.Authenticator.ValidationException(translatable('We need more that two items!'))
Exemple #3
0
    def initialize(self, values):
        '''
        Simply check if we have
        at least one group in the list
        '''

        # To avoid problems, we only check data if values are passed
        # If values are not passed in, form data will only be available after
        # unserialization, and at this point all will be default values
        # so self.groups.value will be []
        if values is not None and len(self.groups.value) < 2:
            raise auths.Authenticator.ValidationException(
                translatable('We need more that two items!'))
Exemple #4
0
class SampleAuth(auths.Authenticator):
    '''
    This class represents a sample authenticator.
    
    As this, it will provide:
       * The authenticator functionality 
          * 3 Groups, "Mortals", "Gods" and "Daemons", just random group names selected.. :-),
            plus groups that we enter at Authenticator form, from admin interface.
          * Search of groups (inside the 3 groups used in this sample plus entered)
          * Search for people (will return the search string + 000...999 as usernames)
       * The Required form description for administration interface, so admins can create
         new authenticators of this kind. 
       
    In this sample, we will provide a simple standard auth, with owner drawn
    login form that will simply show users that has been created and allow web user
    to select one of them.
       
    For this class to get visible at administration client as a authenticator type,
    we MUST register it at package __init__

    :note: At class level, the translations must be simply marked as so
    using ugettext_noop. This is done in this way because we will translate 
    the string when it is sent to the administration client.
    '''

    #: Name of type, used at administration interface to identify this
    #: authenticator (i.e. LDAP, SAML, ...)
    #: This string will be translated when provided to admin interface
    #: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
    #: if you want so it can be translated.
    typeName = translatable('Sample Authenticator')

    #: Name of type used by Managers to identify this type of service
    #: We could have used here the Class name, but we decided that the
    #: module implementator will be the one that will provide a name that
    #: will relation the class (type) and that name.
    typeType = 'SampleAuthenticator'

    #: Description shown at administration level for this authenticator.
    #: This string will be translated when provided to admin interface
    #: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
    #: if you want so it can be translated.
    typeDescription = translatable('Sample dummy authenticator')

    #: Icon file, used to represent this authenticator at administration interface
    #: This file should be at same folder as this class is, except if you provide
    #: your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
    iconFile = 'auth.png'

    #: Mark this authenticator as that the users comes from outside the UDS
    #: database, that are most authenticator (except Internal DB)
    #: True is the default value, so we do not need it in fact
    # isExternalSource = True

    #: If we need to enter the password for this user when creating a new
    #: user at administration interface. Used basically by internal authenticator.
    #: False is the default value, so this is not needed in fact
    #: needsPassword = False

    #: Label for username field, shown at administration interface user form.
    userNameLabel = translatable('Fake User')

    # Label for group field, shown at administration interface user form.
    groupNameLabel = translatable('Fake Group')

    #: Definition of this type of authenticator form
    #: We will define a simple form where we will use a simple
    #: list editor to allow entering a few group names

    groups = gui.EditableList(label=translatable('Groups'),
                              values=['Gods', 'Daemons', 'Mortals'])

    def initialize(self, values):
        '''
        Simply check if we have
        at least one group in the list
        '''

        # To avoid problems, we only check data if values are passed
        # If values are not passed in, form data will only be available after
        # unserialization, and at this point all will be default values
        # so self.groups.value will be []
        if values is not None and len(self.groups.value) < 2:
            raise auths.Authenticator.ValidationException(
                translatable('We need more that two items!'))

    def searchUsers(self, pattern):
        '''
        Here we will receive a pattern for searching users.
        
        This method is invoked from interface, so an administrator can search users.
        
        If we do not provide this method, the authenticator will not provide search
        facility for users. In our case, we will simply return a list of users
        (array of dictionaries with ids and names) with the pattern plus 1..10 
        '''
        return [{
            'id': '{0}-{1}'.format(pattern, a),
            'name': '{0} number {1}'.format(pattern, a)
        } for a in range(1, 10)]

    def searchGroups(self, pattern):
        '''
        Here we we will receive a patter for searching groups.
        
        In this sample, we will try to locate elements that where entered at
        sample authenticator form (when created), and return the ones that
        contains the pattern indicated.
        '''
        pattern = pattern.lower()
        res = []
        for g in self.groups.value:
            if g.lower().find(pattern) != -1:
                res.append({'id': g, 'name': ''})
        return res

    def authenticate(self, username, credentials, groupsManager):
        '''
        This method is invoked by UDS whenever it needs an user to be authenticated.
        It is used from web interface, but also from administration interface to
        check credentials and access of user.
        
        The tricky part of this method is the groupsManager, but it's easy to
        understand what is used it for.
        
        Imagine some authenticator, for example, an LDAP. It has its users, it has
        its groups, and it has it relations (which user belongs to which group).
        
        Now think about UDS. UDS know nothing about this, it only knows what
        the administator has entered at admin interface (groups mainly, but he can
        create users also).
        
        UDS knows about this groups, but we need to relation those with the ones
        know by the authenticator. 
        
        To do this, we have created a simple mechanism, where the authenticator
        receives a groupsManager, that knows all groups known by UDS, and has
        the method so the authenticator can say, for the username being validated,
        to which uds groups it belongs to.
        
        This is done using the :py:meth:uds.core.auths.GroupsManager.GroupsManager.validate
        method of the provided groups manager.
        
        At return, UDS will do two things:
           * If there is no group inside the groupsManager mareked as valid, it will
             denied access.
           * If there is some groups marked as valid, it will refresh the known
             UDS relations (this means that the database will be refresehd so the user
             has valid groups).
             
        This also means that the group membership is only checked at user login (well,
        in fact its also checked when an administrator tries to modify an user)
        
        So, authenticate must not also validate the user credentials, but also
        indicate the group membership of this user inside UDS. 
        
        :note: groupsManager is an in/out parameter
        '''
        if username != credentials:  # All users with same username and password are allowed
            return False

        # Now the tricky part. We will make this user belong to groups that contains at leat
        # two letters equals to the groups names known by UDS
        # For this, we will ask the groups manager for the groups names, and will check that and,
        # if the user match this criteria, will mark that group as valid
        for g in groupsManager.getGroupsNames():
            if len(set(g.lower()).intersection(username.lower())) >= 2:
                groupsManager.validate(g)

        return True

    def getGroups(self, username, groupsManager):
        '''
        As with authenticator part related to groupsManager, this
        method will fill the groups to which the specified username belongs to.
        
        We have to fill up groupsManager from two different places, so it's not
        a bad idea to make a method that get the "real" authenticator groups and
        them simply call to :py:meth:uds.core.auths.GroupsManager.GroupsManager.validate
        
        In our case, we simply repeat the process that we also do at authenticate
        '''
        for g in groupsManager.getGroupsNames():
            if len(set(g.lower()).intersection(username.lower())) >= 2:
                groupsManager.validate(g)

    def getHtml(self, request):
        '''
        If we override this method from the base one, we are telling UDS
        that we want to draw our own authenticator.
        
        This way, we can do whataver we want here (for example redirect to a site
        for a single sign on) generation our ouwn html (and javascript ofc).
        
        '''
        # Here there is a sample, commented out
        # In this sample, we will make a list of valid users, and when clicked,
        # it will fill up original form with username and same password, and submit it.
        #res = ''
        #for u in self.dbAuthenticator().users.all():
        #    res += '<a class="myNames" id="{0}" href="">{0}</a><br/>'.format(u.name)
        #
        #res += '<script type="text/javascript">$(".myNames").click(function() { '
        #res += '$("#id_user").val(this.id); $("#id_password").val(this.id); $("#loginform").submit(); return false;});</script>'
        #return res

        # I know, this is a bit ugly, but this is just a sample :-)

        res = '<p>Login name: <input id="logname" type="text"/></p>'
        res += '<p><a href="" onclick="window.location.replace(\'' + self.callbackUrl(
        ) + '?user='******'\' + $(\'#logname\').val()); return false;">Login</a></p>'
        return res

    def authCallback(self, parameters):
        '''
        We provide this as a sample of callback for an user.
        We will accept all petitions that has "user" parameter
        
        This method will get invoked by url redirections, probably by an SSO.
        
        The idea behind this is that we can provide:
            * Simple user/password authentications
            * Own authentications (not UDS, authenticator "owned"), but with no redirections
            * Own authentications via redirections (as most SSO will do)
            
        Here, we will receive the parameters for this
        '''
        user = parameters.get('user', None)

        return user

    def createUser(self, usrData):
        '''
        This method provides a "check oportunity" to authenticators for users created
        manually at administration interface.
        
        If we do not provide this method, the administration interface will not allow
        to create new users "by hand", i mean, the "new" options from menus will dissapear.
        
        usrData is a dictionary that contains the input parameters from user, 
        with at least name, realName, comments, state & password.
        
        We can modify this parameters, we can modify ALL, but name is not recommended to 
        modify it unles you know what you are doing.
        
        Here, we will set the state to "Inactive" and realName to the same as username, but twice :-)
        '''
        from uds.core.util.State import State
        usrData['realName'] = usrData['name'] + ' ' + usrData['name']
        usrData['state'] = State.INACTIVE

    def modifyUser(self, usrData):
        '''
        This method provides a "check opportunity" to authenticator for users modified
        at administration interface.
        
        If we do not provide this method, nothing will happen (default one does nothing, but
        it's valid).
        
        usrData is a dictionary that contains the input parameters from user, 
        with at least name, realName, comments, state & password.
        
        We can modify this parameters, we can modify ALL, but name is not recommended to 
        modify it unless you know what you are doing.
        
        Here, we will simply update the realName of the user, and (we have to take care
        this this kind of things) modify the userName to a new one, the original plus '-1'
        '''
        usrData['realName'] = usrData['name'] + ' ' + usrData['name']
        usrData['name'] = usrData['name'] + '-1'
Exemple #5
0
class Provider(ServiceProvider):
    '''
    This class represents the sample services provider
    
    In this class we provide:
       * The Provider functionality
       * The basic configuration parameters for the provider
       * The form fields needed by administrators to configure this provider
       
       :note: At class level, the translation must be simply marked as so
       using ugettext_noop. This is so cause we will translate the string when
       sent to the administration client.
       
    For this class to get visible at administration client as a provider type,
    we MUST register it at package __init__.
    
    '''
    #: What kind of services we offer, this are classes inherited from Service
    offers = [ServiceOne, ServiceTwo]
    #: Name to show the administrator. This string will be translated BEFORE
    #: sending it to administration interface, so don't forget to
    #: mark it as translatable (using ugettext_noop)
    typeName = translatable('Sample Provider') 
    #: Type used internally to identify this provider
    typeType = 'SampleProvider'
    #: Description shown at administration interface for this provider
    typeDescription = translatable('Sample (and dummy) service provider')
    #: Icon file used as icon for this provider. This string will be translated 
    #: BEFORE sending it to administration interface, so don't forget to
    #: mark it as translatable (using ugettext_noop)
    iconFile = 'provider.png'
    
    # now comes the form fields
    # There is always two fields that are requested to the admin, that are:
    # Service Name, that is a name that the admin uses to name this provider
    # Description, that is a short description that the admin gives to this provider
    # Now we are going to add a few fields that we need to use this provider
    # Remember that these are "dummy" fields, that in fact are not required
    # but used for sample purposes
    # If we don't indicate an order, the output order of fields will be
    # "random"
    
    #: Remote host. Here core will translate label and tooltip, remember to
    #: mark them as translatable using ugettext_noop.
    remoteHost = gui.TextField(oder=1,
                     length = 64,  
                     label = translatable('Remote host'),
                     tooltip = translatable('This fields contains a remote host'),
                     required = True,
                 )
    #: Name of your pet (sample, not really needed :-) )
    petName = gui.TextField(order=2,
                  length = 32,  
                  label = translatable('Your pet\'s name'),
                  tooltip = translatable('If you like, write the name of your pet'),
                  requred = False,
                  defvalue = 'Tux' #: This will not get translated
              )
    #: Age of Methuselah (matusalén in spanish)
    #: in Spain there is a well-known to say that something is very old, 
    #: "Tiene mas años que matusalén"(is older than Methuselah)
    methAge = gui.NumericField(order = 3,
                  length = 4, # That is, max allowed value is 9999  
                  label = translatable('Age of Methuselah'),
                  tooltip = translatable('If you know it, please, tell me!!!'),
                  required = True, #: Numeric fields have always a value, so this not really needed
                  defvalue = '4500'
              )
     
    #: Is Methuselah istill alive?
    methAlive = gui.CheckBoxField(order = 4,
                    label = translatable('Is Methuselah still alive?'),
                    tooltip = translatable('If you fail, this will not get saved :-)'),
                    required = True, #: Also means nothing. Check boxes has always a value
                    defvalue = gui.TRUE #: By default, at new item, check this
                ) 
    
    # There is more fields type, but not here the best place to cover it
    def initialize(self, values = None):
        '''
        We will use the "autosave" feature for form fields, that is more than
        enought for most providers. (We simply need to store data provided by user
        and, maybe, initialize some kind of connection with this values).
        
        Normally provider values are rally used at sevice level, cause we never
        instantiate nothing except a service from a provider.
        '''
        
        # If you say meth is alive, you are wrong!!! (i guess..)
        # values are only passed from administration client. Internals 
        # instantiations are always empty.
        if values is not None and self.methAlive.isTrue():
            raise ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)'))

    # Marshal and unmarshal are defaults ones, also enought
    
    # As we use "autosave" fields feature, dictValues is also provided by
    # base class so we don't have to mess with all those things...
    
    @staticmethod
    def test(env, data):
        '''
        Create your test method here so the admin can push the "check" button
        and this gets executed.
        Args:
            env: environment passed for testing (temporal environment passed)
            
            data: data passed for testing (data obtained from the form 
            definition)
            
        Returns: 
            Array of two elements, first is True of False, depending on test 
            (True is all right, false is error),
            second is an String with error, preferably internacionalizated..
        
        In this case, wi well do nothing more that use the provider params
        
        Note also that this is an static method, that will be invoked using
        the admin user provided data via administration client, and a temporary
        environment that will be erased after invoking this method
        '''
        try:
            # We instantiate the provider, but this may fail...
            instance = Provider(env, data)
            logger.debug('Methuselah has {0} years and is {1} :-)'
                         .format(instance.methAge.value, instance.methAlive.value))
        except ServiceProvider.ValidationException as e:
            # If we say that meth is alive, instantiation will 
            return [False, str(e)]
        except Exception as e:
            logger.exception("Exception caugth!!!")
            return [False, str(e)]
        return [True, _('Nothing tested, but all went fine..')]

    # Congratulations!!!, the needed part of your first simple provider is done!
    # Now you can go to administration panel, and check it
    #
    # From now onwards, we implement our own methods, that will be used by, 
    # for example, services derived from this provider
    def host(self):
        '''
        Sample method, in fact in this we just return 
        the value of host field, that is an string
        '''
        return self.remoteHost.value
    
    
    def methYears(self):
        '''
Exemple #6
0
class ServiceOne(Service):
    '''
    Basic service, the first part (variables) include the description of the service.
    
    Remember to fill all variables needed, but at least you must define:
        * typeName
        * typeType
        * typeDescription
        * iconFile (defaults to service.png)
        * publicationType, type of publication in case it needs publication. 
          If this is not provided, core will assume that the service do not 
          needs publishing.
        * deployedType, type of deployed user service. Do not forget this!!!
        
    The rest of them can be ommited, but its recommended that you fill all
    declarations shown in this sample (that in fact, are all)
    
    This description informs the core what this service really provides,
    and how this is done. Look at description of class variables for more
    information.
    
    '''
    #: Name to show the administrator. This string will be translated BEFORE
    #: sending it to administration interface, so don't forget to
    #: mark it as translatable (using ugettext_noop)
    typeName = translatable('Sample Service One')
    #: Type used internally to identify this provider
    typeType = 'SampleService1'
    #: Description shown at administration interface for this provider
    typeDescription = translatable('Sample (and dummy) service ONE')
    #: Icon file used as icon for this provider. This string will be translated
    #: BEFORE sending it to administration interface, so don't forget to
    #: mark it as translatable (using ugettext_noop)
    iconFile = 'service.png'

    # Functional related data

    #: If the service provides more than 1 "deployed user" (-1 = no limit,
    #: 0 = ???? (do not use it!!!), N = max number to deploy
    maxDeployed = -1
    #: If we need to generate "cache" for this service, so users can access the
    #: provided services faster. Is usesCache is True, you will need also
    #: set publicationType, do take care about that!
    usesCache = False
    #: Tooltip shown to user when this item is pointed at admin interface, none
    #: because we don't use it
    cacheTooltip = translatable('None')
    #: If we need to generate a "Level 2" cache for this service (i.e., L1
    #: could be running machines and L2 suspended machines)
    usesCache_L2 = False
    #: Tooltip shown to user when this item is pointed at admin interface, None
    #: also because we don't use it
    cacheTooltip_L2 = translatable('None')

    #: If the service needs a s.o. manager (managers are related to agents
    #: provided by services itselfs, i.e. virtual machines with actors)
    needsManager = False
    #: If true, the system can't do an automatic assignation of a deployed user
    #: service from this service
    mustAssignManually = False

    #: Types of publications (preparated data for deploys)
    #: In our case, we do no need a publication, so this is None
    publicationType = None
    #: Types of deploys (services in cache and/or assigned to users)
    deployedType = SampleUserDeploymentOne

    # Now the form part, this service will have only two "dummy" fields
    # If we don't indicate an order, the output order of fields will be
    # "random"

    colour = gui.ChoiceField(
        order=1,
        label=translatable('Colour'),
        tooltip=translatable('Colour of the field'),
        # In this case, the choice can have none value selected by default
        required=True,
        values=[
            gui.choiceItem('red', 'Red'),
            gui.choiceItem('green', 'Green'),
            gui.choiceItem('blue', 'Blue'),
            gui.choiceItem('nonsense', 'Blagenta')
        ],
        defvalue='1'  # Default value is the ID of the choicefield
    )

    passw = gui.PasswordField(
        order=2,
        label=translatable('Password'),
        tooltip=translatable('Password for testing purposes'),
        required=True,
        defvalue='1234'  #: Default password are nonsense?? :-)
    )

    baseName = gui.TextField(
        order=3,
        label=translatable('Services names'),
        tooltip=translatable('Base name for this user services'),
        # In this case, the choice can have none value selected by default
        required=True,
        defvalue=''  # Default value is the ID of the choicefield
    )

    def initialize(self, values):
        '''
        We check here form values to see if they are valid.
        
        Note that we check them throught FROM variables, that already has been
        initialized by __init__ method of base class, before invoking this.
        '''

        # We don't need to check anything, bat because this is a sample, we do
        # As in provider, we receive values only at new Service creation,
        # so we only need to validate params if values is not None
        if values is not None:
            if self.colour.value == 'nonsense':
                raise Service.ValidationException(
                    'The selected colour is invalid!!!')

    # Services itself are non testeable right now, so we don't even have
    # to provide one!!!

    # Congratulations!!!, the needed part of your first simple service is done!
    # Now you can go to administration panel, and check it
    #
    # From now onwards, we implement our own methods, that will be used by,
    # for example, services derived from this provider

    def getColour(self):
        '''
        Simply returns colour, for deployed user services.
        
        Remember that choiceField.value returns the id part of the ChoiceItem
        '''
        return self.colour.value

    def getPassw(self):
        '''
        Simply returns passwd, for deloyed user services
        '''
        return self.passw.value

    def getBaseName(self):
        '''
        '''
        return self.baseName.value