source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/ndgSecurity.py @ 2949

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/ndgSecurity.py@2949
Revision 2949, 9.1 KB checked in by pjkersha, 12 years ago (diff)

Makefile: fixed install target

ows_server/ows_server/models/ndgSecurity.py:

  • include ows_server.lib.base import to enable refs to 'g' global.
  • fixed g.securityCfg.acCACertFilePathList and g.securityCfg.acIssuer var refs

ows_server/ows_server/lib/security_util.py:

Line 
1import sys # tracefile config param may be set to e.g. sys.stderr
2import urllib2
3import socket
4
5from ows_server.lib.base import *
6from pylons import request
7import logging
8log = logging.getLogger(__name__)
9
10from ows_common.exception_report import OwsError
11from ows_server.lib.security_util import SecuritySession
12from ndg.security.common.SessionMgr import SessionMgrClient, SessionNotFound,\
13    SessionCertTimeError, SessionExpired, InvalidSession, \
14    AttributeRequestDenied
15   
16def HandleSecurity(securityElement, securityTokens):
17    return SecurityHandler(securityElement, securityTokens)()
18
19class URLCannotBeOpened(Exception):
20    """Raise from canURLBeOpened SecurityHandler class method
21    if URL is invalid - this method is used to check the AA
22    service"""
23
24class SecurityHandler(object):
25    """Make access control decision based on CSML constraint and user security
26    token"""
27   
28    AccessAllowedMsg = "Access Allowed"
29    InvalidAttributeCertificate = \
30            "The certificate containing your authorisation roles is invalid"
31    NotLoggedInMsg = 'Not Logged in'
32    SessionExpiredMsg = 'Session has expired.  Please re-login'
33    InvalidSessionMsg = 'Session is invalid.  Please try re-login'
34    InvalidSecurityCondition = 'Invalid Security Condition'
35
36    def __init__(self, securityElement, securityTokens):
37        """Initialise settings for WS-Security and SSL for SOAP
38        call to Session Manager
39       
40        @type: ? TODO: set type
41        @param securityElement: CSML security constraint containing role and
42        Attribute Authority URI
43       
44        @type: pylons.session
45        @param securityTokens: dict-like session object containing security
46        tokens"""
47       
48        self.securityElement = securityElement
49        self.securityTokens = securityTokens
50
51
52    def __call__(self, **kw):
53        """Convenience wrapper for checkAccess"""
54        return self.checkAccess(**kw)
55
56
57    def checkAccess(self, securityElement=None, securityTokens=None):
58        """Make an access control decision based on whether the user is
59        authenticated and has the required roles
60       
61        @type: ElementTree Element
62        @param securityElement: MOES security constraint containing role and
63        Attribute Authority URI. In xml, could look like:
64        <moles:effect>allow</moles:effect>
65            <moles:simpleCondition>
66            <moles:dgAttributeAuthority>https://glue.badc.rl.ac.uk/AttributeAuthority</moles:dgAttributeAuthority>
67            <moles:attrauthRole>coapec</moles:attrauthRole>
68        </moles:simpleCondition>
69        NB: xmlns:moles="http://ndg.nerc.ac.uk/moles"
70       
71        @type: pylons.session
72        @param securityTokens: dict-like session object containing security
73        tokens.  Resets equivalent object attribute."""
74         
75        # tokens and element may be set from __init__ or as args to this
76        # method.  If the latter copy them into self 
77        if securityTokens:
78            self.securityTokens = securityTokens
79                           
80        if securityElement:
81            self.securityElement=securityElement
82     
83        # Check self.securityTokens - if not set then the user mustn't be
84        # logged in.  This situation is possible if a user has been denied
85        # access to data and then tried to logout - after log out they are
86        # redirected back to the page where they tried accessing data but this
87        # time they will have no security credential set
88        if not self.securityTokens:
89            # Try to recover and do something sensible
90            #
91            # TODO: this adds insult to injury if the person has just been
92            # denied access to data.  Instead do a redirect back to the
93            # discovery page?
94            # P J Kershaw 10/08/07
95            log.info("Exiting from Gatekeeper: user is not logged in")
96            return False, self.__class__.NotLoggedInMsg
97           
98        xpathr='{http://ndg.nerc.ac.uk/moles}simpleCondition/{http://ndg.nerc.ac.uk/moles}attrauthRole'
99        xpathaa='{http://ndg.nerc.ac.uk/moles}simpleCondition/{http://ndg.nerc.ac.uk/moles}dgAttributeAuthority'
100        roleE,aaE=self.securityElement.find(xpathr),self.securityElement.find(xpathaa)
101        if roleE is None:
102            log.error("Gatekeeper: role not found in dataset element: %s" % \
103                      self.securityElement)
104            return False, self.__class__.InvalidSecurityCondition
105       
106        self.reqRole=roleE.text
107       
108        # Check Attribute Authority address
109        try:
110            SecurityHandler.urlCanBeOpened(aaE.text)
111        except (URLCannotBeOpened, AttributeError):
112            # Catch situation where either Attribute Authority address in the
113            # data invalid or none was set.  In this situation verify
114            # against the Attribute Authority set in the config
115            log.info('Gatekeeper: Attribute Authority address is invalid ' + \
116                     'in data "%s" - defaulting to config file setting' % \
117                     self.securityElement)
118            self.reqAAURI = g.securityCfg.aaURI
119   
120        # Create Session Manager client
121        self.smClnt = SessionMgrClient(uri=self.securityTokens['h'],
122                    sslCACertFilePathList=g.securityCfg.sslCACertFilePathList,
123                    sslPeerCertCN=g.securityCfg.sslPeerCertCN,
124                    signingCertFilePath=g.securityCfg.wssCertFilePath,
125                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath,
126                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd,
127                    caCertFilePathList=g.securityCfg.wssCACertFilePathList,
128                    tracefile=g.securityCfg.tracefile)       
129       
130        return self.__checkAttCert()
131           
132
133   
134    def __checkAttCert(self):
135        """Check to see if the Session Manager can deliver an Attribute
136        Certificate with the required role to gain access to the resource
137        in question"""
138           
139        try:
140            # Make request for attribute certificate
141            attCert = self.smClnt.getAttCert(attAuthorityURI=self.reqAAURI,
142                                         sessID=self.securityTokens['sid'],
143                                         reqRole=self.reqRole)
144        except AttributeRequestDenied, e:
145            log.info(\
146                "Gatekeeper - request for attribute certificate denied: %s"%e)
147            return False, str(e)
148       
149        except SessionNotFound, e:
150            # Clear the security details from the session object
151            SecuritySession.delete()
152            log.info("Gatekeeper - no session found: %s" % e)
153            return False, self.__class__.NotLoggedInMsg
154
155        except SessionExpired, e:
156            # Clear the security details from the session object
157            SecuritySession.delete()
158            log.info("Gatekeeper - session expired: %s" % e)
159            return False, self.__class__.SessionExpiredMsg
160
161        except SessionCertTimeError, e:
162            # Clear the security details from the session object
163            SecuritySession.delete()
164            log.info("Gatekeeper - session cert. time error: %s" % e)
165            return False, self.__class__.InvalidSessionMsg
166           
167        except InvalidSession, e:
168            SecuritySession.delete()
169            log.info("Gatekeeper - invalid user session: %s" % e)
170            return False, self.__class__.InvalidSessionMsg
171
172        except Exception, e:
173            raise OwsError, "Gatekeeper request for attribute certificate: "+\
174                            str(e)
175                           
176        # Check attribute certificate is valid
177        attCert.certFilePathList = g.securityCfg.acCACertFilePathList
178        attCert.isValid(raiseExcep=True)
179           
180        # Check it's issuer is as expected
181        if attCert.issuer != g.securityCfg.acIssuer:
182            log.info('Gatekeeper - access denied: Attribute Certificate ' + \
183                'issuer DN, "%s" ' % attCert.issuer + \
184                'must match this data provider\'s Attribute Authority ' + \
185                'DN: "%s"' % g.securityCfg.acIssuer)
186            return False, self.__class__.InvalidAttributeCertificate
187       
188        log.info(\
189 'Gatekeeper: access granted for user "%s" to "%s" secured with role "%s"' % \
190                 (attCert.userId, self.securityElement, self.reqRole) + \
191                 'with attribute certificate:\n\n%s' % attCert) 
192                     
193        return True, self.__class__.AccessAllowedMsg
194
195    @classmethod
196    def urlCanBeOpened(cls, url, timeout=5, raiseExcep=True):
197       """Check url can be opened - adapted from
198       http://mail.python.org/pipermail/python-list/2004-October/289601.html
199       """
200   
201       found = False
202       defTimeOut = socket.getdefaulttimeout()
203       try:
204           socket.setdefaulttimeout(timeout)
205
206           try:
207               urllib2.urlopen(url)
208           except (urllib2.HTTPError, urllib2.URLError,
209                   socket.error, socket.sslerror):
210               if raiseExcep:
211                   raise URLCannotBeOpened
212           
213           found = True
214         
215       finally:
216           socket.setdefaulttimeout(defTimeOut)
217           
218       return found       
Note: See TracBrowser for help on using the repository browser.