1 | # Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council). |
---|
2 | # This software may be distributed under the terms of the |
---|
3 | # Q Public License, version 1.0 or later. |
---|
4 | # http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt |
---|
5 | """ |
---|
6 | Manages interface to NDG documents and data, including caching |
---|
7 | """ |
---|
8 | |
---|
9 | from cache import Cache |
---|
10 | from csml_cache import CSMLExtractCache |
---|
11 | import os, logging |
---|
12 | from ndgUtils import ndgRetrieve, ndgObject, xmlHandler2 |
---|
13 | from pylons import request, session |
---|
14 | |
---|
15 | from pylons import g # for handle to access control PEP interface |
---|
16 | try: |
---|
17 | from ndg.security.common.authz.pdp import PDPError |
---|
18 | from ndg.security.common.authz.pep import PEPError |
---|
19 | except ImportError, e: |
---|
20 | from warnings import warn |
---|
21 | warn(__name__ + ": access control is disabled: %s" % e, RuntimeWarning) |
---|
22 | |
---|
23 | class ndgInterface: |
---|
24 | |
---|
25 | def __init__(self): |
---|
26 | ''' Instantiate with three level cache: |
---|
27 | - a file cache |
---|
28 | - a xmlhandler object cache, and |
---|
29 | - a parsed CSML object cache.''' |
---|
30 | |
---|
31 | self.CSMLDataCache=CSMLExtractCache( |
---|
32 | request.environ['paste.config']['app_conf']['tmp_dir'],max_size=10) |
---|
33 | self.CSMLDocCache=Cache(max_size=10) |
---|
34 | self.XMLHCache=Cache(max_size=10) |
---|
35 | |
---|
36 | |
---|
37 | def GetXML(self,uri,outputSchema='', useCache=True): |
---|
38 | ''' |
---|
39 | This method provides a secure interface to the server |
---|
40 | document cache and a remote NDG exist. It is assumed that |
---|
41 | the local filesystem is protected in that you can't get to |
---|
42 | files except via the CSML api |
---|
43 | @param uri: ndg format uri to locate doc from |
---|
44 | @keyword outputSchema: format to return doc in |
---|
45 | @keyword useCache: check for data in the cache and use this, if set to |
---|
46 | True (the default) |
---|
47 | ''' |
---|
48 | # Note that this method should not be used to obtain |
---|
49 | #unsecured discovery documents, these are called directly |
---|
50 | #in the retrieve controller! |
---|
51 | |
---|
52 | logging.info("Getting XML from uri, '%s' (outputschema: '%s')" \ |
---|
53 | %(uri, outputSchema)) |
---|
54 | try: |
---|
55 | ndgO=ndgObject(uri) |
---|
56 | localFile=0 |
---|
57 | except ValueError: |
---|
58 | ''' It's a local file not an ndg identifier ''' |
---|
59 | logging.info("File appears to be local - look for it there...") |
---|
60 | ndgO=uri |
---|
61 | localFile=1 |
---|
62 | |
---|
63 | if session and 'ndgCleared' in session: |
---|
64 | cleared=session['ndgCleared'] |
---|
65 | else: |
---|
66 | cleared=None |
---|
67 | |
---|
68 | if outputSchema or not useCache: |
---|
69 | #bypass the cache ... |
---|
70 | status,xmlh=ndgRetrieve(ndgO, |
---|
71 | request.environ['ndgConfig'], |
---|
72 | output=outputSchema, |
---|
73 | discovery=g.standalone) |
---|
74 | else: |
---|
75 | try: |
---|
76 | xmlh=self.XMLHCache[uri] |
---|
77 | status=1 |
---|
78 | logging.info('XMLH Cache hit for [%s]'%uri) |
---|
79 | except: |
---|
80 | logging.info('XMLH Cache miss for [%s]'%uri) |
---|
81 | if localFile: |
---|
82 | status,xmlH=self.__getLocal(uri) |
---|
83 | else: |
---|
84 | status,xmlh=ndgRetrieve(ndgO, |
---|
85 | request.environ['ndgConfig'], |
---|
86 | output=outputSchema, |
---|
87 | discovery=g.standalone) |
---|
88 | if status: |
---|
89 | self.XMLHCache[uri]=xmlh |
---|
90 | |
---|
91 | if not status: return status,xmlh |
---|
92 | |
---|
93 | # convert doc to an XML tree |
---|
94 | xmlh=xmlHandler2.xmlHandler(xmlh,string=1) |
---|
95 | |
---|
96 | # valid values of the return objects SHOULD BE |
---|
97 | # ok: status=1, xmlh=an xml handler instance. |
---|
98 | # exceptions, status=0, xmlh='Exception(e)' |
---|
99 | |
---|
100 | status,xmlh=self.__gatekeep(ndgO,xmlh) |
---|
101 | if status: |
---|
102 | if cleared is None: |
---|
103 | session['ndgCleared']=[uri] |
---|
104 | else: |
---|
105 | session['ndgCleared'].append(uri) |
---|
106 | session.save() |
---|
107 | |
---|
108 | return status,xmlh |
---|
109 | |
---|
110 | |
---|
111 | def __gatekeep(self,uri,x): |
---|
112 | ''' This is the NDG gatekeeper ''' |
---|
113 | if 'ndgSec' in session: |
---|
114 | securityTokens=session['ndgSec'] |
---|
115 | else: |
---|
116 | securityTokens=None |
---|
117 | |
---|
118 | if not hasattr(g, 'pep'): |
---|
119 | if not g.standalone: |
---|
120 | raise PEPError(\ |
---|
121 | "Security is disabled but the standalone flag is set to False") |
---|
122 | |
---|
123 | logging.info("__gatekeep: access control is disabled - standalone " + \ |
---|
124 | "config flag is set") |
---|
125 | |
---|
126 | try: |
---|
127 | # Arguments are: a handle to the resource and a handle to the users |
---|
128 | # security tokens |
---|
129 | g.pep(dict(uri=uri, doc=x), securityTokens, None) |
---|
130 | return True, x |
---|
131 | |
---|
132 | except PDPError, e: |
---|
133 | # Caught a known access control condition |
---|
134 | return False, 'Access Denied for %s %s' % (uri, e) |
---|
135 | |
---|
136 | |
---|
137 | def __getLocal(self,uri): |
---|
138 | ''' Returns a local csml file (used for testing) ''' |
---|
139 | csml_dir = request.environ['paste.config']['app_conf']['csml_dir'] |
---|
140 | path = os.path.join(csml_dir, file) |
---|
141 | if os.path.exists(path+'.csml'): |
---|
142 | f = path+'.csml' |
---|
143 | elif os.path.exists(path+'.xml'): |
---|
144 | f = path +'.xml' |
---|
145 | else: |
---|
146 | return 0, '<p>Cannot find CSML file %s</p>' % file |
---|
147 | r=f.read() |
---|
148 | return 1,r |
---|
149 | |
---|
150 | |
---|
151 | |
---|
152 | interface=ndgInterface() |
---|