Skip to content
Snippets Groups Projects
Commit 5f0a9072 authored by Vermaat's avatar Vermaat
Browse files

Various security related fixes to url routing.

Renamed SOAP webservice from MutalyzerService to Mutalyzer.
Updated copyright years in HTML template.
Added test checking availability of WSDL file.



git-svn-id: https://humgenprojects.lumc.nl/svn/mutalyzer/trunk@160 eb6bd6ab-9ccd-42b9-aceb-e2899b4a52f1
parent b86464a4
No related branches found
No related tags found
No related merge requests found
...@@ -2,17 +2,28 @@ ...@@ -2,17 +2,28 @@
""" """
Tests for the SOAP interface to Mutalyzer. Tests for the SOAP interface to Mutalyzer.
@todo: Test availability of the WSDL file.
""" """
import logging; logging.raiseExceptions = 0 import logging; logging.raiseExceptions = 0
import urllib2
from suds.client import Client from suds.client import Client
from suds import WebFault from suds import WebFault
import unittest import unittest
WSDL_URL = 'http://mutalyzer.martijn/services/?wsdl' WSDL_URL = 'http://mutalyzer.martijn/services/?wsdl'
class TestWSDL(unittest.TestCase):
"""
Test the Mutalyzer SOAP interface WSDL description.
"""
def test_wsdl(self):
"""
Test if the WSDL is available and looks somewhat sensible.
"""
wsdl = urllib2.urlopen(WSDL_URL).read()
self.assertTrue(wsdl.startswith("<?xml version='1.0' encoding='UTF-8'?>"))
self.assertTrue('name="Mutalyzer"' in wsdl)
class TestWebservice(unittest.TestCase): class TestWebservice(unittest.TestCase):
""" """
Test the Mutalyzer SOAP interface. Test the Mutalyzer SOAP interface.
......
...@@ -8,6 +8,8 @@ Uses WebTest, see: ...@@ -8,6 +8,8 @@ Uses WebTest, see:
http://blog.ianbicking.org/2010/04/02/webtest-http-testing/ http://blog.ianbicking.org/2010/04/02/webtest-http-testing/
I just installed webtest by 'easy_install webtest'. I just installed webtest by 'easy_install webtest'.
@todo: Tests for /upload, /getGS, and /Variant_info.
""" """
import re import re
...@@ -293,7 +295,7 @@ class TestWSGI(unittest.TestCase): ...@@ -293,7 +295,7 @@ class TestWSGI(unittest.TestCase):
""" """
r = self.app.get('/documentation') r = self.app.get('/documentation')
self.assertEqual(r.content_type, 'text/html') self.assertEqual(r.content_type, 'text/html')
r.mustcontain('Web Service: MutalyzerService') r.mustcontain('Web Service: Mutalyzer')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -29,10 +29,6 @@ import logging; logging.basicConfig() ...@@ -29,10 +29,6 @@ import logging; logging.basicConfig()
# $ cd soaplib # $ cd soaplib
# $ sudo python setup.py install # $ sudo python setup.py install
# Other tree:
# https://github.com/cuker/soaplib/
# https://github.com/cuker/soaplib/commit/1a248ba1421c57738c6d30333036114c3ed42022
from soaplib.core import Application from soaplib.core import Application
from soaplib.core.service import soap from soaplib.core.service import soap
from soaplib.core.service import DefinitionBase from soaplib.core.service import DefinitionBase
...@@ -227,8 +223,8 @@ class MutalyzerService(DefinitionBase) : ...@@ -227,8 +223,8 @@ class MutalyzerService(DefinitionBase) :
return ret return ret
#getTranscriptsByGene #getTranscriptsByGene
@soap(Mandatory.String, Mandatory.String, Mandatory.Integer, Mandatory.Integer, Mandatory.Integer, @soap(Mandatory.String, Mandatory.String, Mandatory.Integer,
_returns = List.String) Mandatory.Integer, Mandatory.Integer, _returns = List.String)
def getTranscriptsRange(self, build, chrom, pos1, pos2, method) : def getTranscriptsRange(self, build, chrom, pos1, pos2, method) :
"""Get all the transcripts that overlap with a range on a chromosome. """Get all the transcripts that overlap with a range on a chromosome.
...@@ -304,7 +300,8 @@ class MutalyzerService(DefinitionBase) : ...@@ -304,7 +300,8 @@ class MutalyzerService(DefinitionBase) :
#getGeneName #getGeneName
@soap(Mandatory.String, Mandatory.String, Mandatory.String, Mandatory.String, _returns = Mapping) @soap(Mandatory.String, Mandatory.String, Mandatory.String,
Mandatory.String, _returns = Mapping)
def mappingInfo(self, LOVD_ver, build, accNo, variant) : def mappingInfo(self, LOVD_ver, build, accNo, variant) :
"""Search for an NM number in the MySQL database, if the version """Search for an NM number in the MySQL database, if the version
number matches, get the start and end positions in a variant and number matches, get the start and end positions in a variant and
...@@ -631,7 +628,7 @@ class MutalyzerService(DefinitionBase) : ...@@ -631,7 +628,7 @@ class MutalyzerService(DefinitionBase) :
# WSGI application for use with e.g. Apache/mod_wsgi # WSGI application for use with e.g. Apache/mod_wsgi
soap_application = Application([MutalyzerService], soap_application = Application([MutalyzerService],
'http://mutalyzer.nl/2.0/services', # namespace 'http://mutalyzer.nl/2.0/services', # namespace
'MutalyzerService') 'Mutalyzer')
application = wsgi.Application(soap_application) application = wsgi.Application(soap_application)
# We can also use the built-in webserver by executing this file directly # We can also use the built-in webserver by executing this file directly
......
...@@ -41,6 +41,8 @@ port 8080): ...@@ -41,6 +41,8 @@ port 8080):
VERSION = '2.0&nbsp;&beta;-6' VERSION = '2.0&nbsp;&beta;-6'
NOMENCLATURE_VERSION = '2.0' NOMENCLATURE_VERSION = '2.0'
RELEASE_DATE = '12 Jan 2011' RELEASE_DATE = '12 Jan 2011'
WEBSERVICE_LOCATION = '/services'
WSDL_VIEWER = 'templates/wsdl-viewer.xsl'
# Log exceptions to stdout # Log exceptions to stdout
...@@ -51,7 +53,6 @@ import os ...@@ -51,7 +53,6 @@ import os
import bz2 import bz2
import web import web
import urllib import urllib
import urllib2
import site import site
from lxml import etree from lxml import etree
...@@ -111,8 +112,8 @@ urls = ( ...@@ -111,8 +112,8 @@ urls = (
'/Results_(\d+)\.txt', 'BatchResult', '/Results_(\d+)\.txt', 'BatchResult',
'/download/([a-zA-Z-]+\.(?:py|cs))', 'Download', '/download/([a-zA-Z-]+\.(?:py|cs))', 'Download',
'/downloads/([a-zA-Z\._-]+)', 'Downloads', '/downloads/([a-zA-Z\._-]+)', 'Downloads',
'/upload', 'Uploader', '/Reference/([\da-zA-Z\._-]+)', 'Reference',
'/Reference/(.*)', 'Reference' '/upload', 'Uploader'
) )
...@@ -215,12 +216,18 @@ session = web.session.Session(app, ...@@ -215,12 +216,18 @@ session = web.session.Session(app,
class Download: class Download:
""" """
Download file from template directory, processing it with TAL first. Download file from template directory, processing it with TAL first.
@todo: This is a potential security hole.
""" """
def GET(self, file): def GET(self, file):
""" """
@arg file: Filename to download. @arg file: Filename to download.
@type file: string
Be very careful to not call this with anything but an ordinary
filename. A possible security issue is allowing this method to be
called with file='../mutalyzer.conf' for example.
The url routing currently makes sure to only call this with filenames
of the form [a-zA-Z-]+\.(?:py|cs).
""" """
# Process the file with TAL and return the content as a downloadable file. # Process the file with TAL and return the content as a downloadable file.
if not os.path.isfile("templates/" + file): if not os.path.isfile("templates/" + file):
...@@ -236,12 +243,18 @@ class Download: ...@@ -236,12 +243,18 @@ class Download:
class Downloads: class Downloads:
""" """
Download plain text files from /templates/downloads directory. Download plain text files from /templates/downloads directory.
@todo: This is a potential security hole.
""" """
def GET(self, file): def GET(self, file):
""" """
@arg file: Filename to download. @arg file: Filename to download.
@type file: string
Be very careful to not call this with anything but an ordinary
filename. A possible security issue is allowing this method to be
called with file='../../mutalyzer.conf' for example.
The url routing currently makes sure to only call this with filenames
of the form [a-zA-Z\._-]+.
""" """
if not os.path.isfile("templates/downloads/" + file): if not os.path.isfile("templates/downloads/" + file):
raise web.notfound() raise web.notfound()
...@@ -260,6 +273,14 @@ class Reference: ...@@ -260,6 +273,14 @@ class Reference:
def GET(self, file): def GET(self, file):
""" """
@arg file: Filename to download from cache. @arg file: Filename to download from cache.
@type file: string
Be very careful to not call this with anything but an ordinary
filename. A possible security issue is allowing this method to be
called with file='../../mutalyzer.conf' for example.
The url routing currently makes sure to only call this with filenames
of the form [a-zA-Z\._-]+.
""" """
fileName = "%s/%s.bz2" % (C.Retriever.cache, file) fileName = "%s/%s.bz2" % (C.Retriever.cache, file)
if not os.path.isfile(fileName): if not os.path.isfile(fileName):
...@@ -346,7 +367,8 @@ class SyntaxCheck: ...@@ -346,7 +367,8 @@ class SyntaxCheck:
i = web.input() i = web.input()
variant = i.variant variant = i.variant
if variant.find(',') >= 0: if variant.find(',') >= 0:
O.addMessage(__file__, 2, "WCOMMASYNTAX", "Comma's are not allowed in the syntax, autofixed") O.addMessage(__file__, 2, "WCOMMASYNTAX",
"Comma's are not allowed in the syntax, autofixed")
variant = variant.replace(',', '') variant = variant.replace(',', '')
#args["variant"]=variant #args["variant"]=variant
P = Parser.Nomenclatureparser(O) P = Parser.Nomenclatureparser(O)
...@@ -399,7 +421,8 @@ class Snp: ...@@ -399,7 +421,8 @@ class Snp:
O.addMessage(__file__, -1, "INFO", "Received rs%s" % rsId) O.addMessage(__file__, -1, "INFO", "Received rs%s" % rsId)
R = Retriever.Retriever(C.Retriever, O, None) R = Retriever.Retriever(C.Retriever, O, None)
R.snpConvert(rsId) R.snpConvert(rsId)
O.addMessage(__file__, -1, "INFO", "Finished processing rs%s" % rsId) O.addMessage(__file__, -1, "INFO",
"Finished processing rs%s" % rsId)
#if #if
args = { args = {
...@@ -655,6 +678,8 @@ class Check: ...@@ -655,6 +678,8 @@ class Check:
class CheckForward: class CheckForward:
""" """
Set the given variant in the session and redirect to the name checker. Set the given variant in the session and redirect to the name checker.
@todo: Cleaner solution (one without using a session variable).
""" """
def GET(self): def GET(self):
""" """
...@@ -681,16 +706,16 @@ class BatchProgress: ...@@ -681,16 +706,16 @@ class BatchProgress:
""" """
Progress for a batch job. Progress for a batch job.
@todo: The 'progress' template does not exist.
Parameters: Parameters:
- jobID: ID of the job to return progress for. - jobID: ID of the job to return progress for.
- totalJobs: Total number of entries in this job. - totalJobs: Total number of entries in this job.
- ajax: If set, return plain text result. - ajax: If set, return plain text result.
@todo: The 'progress' template does not exist.
""" """
O = Output.Output(__file__, C.Output) O = Output.Output(__file__, C.Output)
attr = {"percentage" : 0} attr = {"percentage": 0}
i = web.input(ajax=None) i = web.input(ajax=None)
try: try:
...@@ -828,6 +853,14 @@ class BatchResult: ...@@ -828,6 +853,14 @@ class BatchResult:
Return raw content (for batch checker results). Return raw content (for batch checker results).
@arg result: Result identifier. @arg result: Result identifier.
@type result: string
Be very careful to not call this with anything but an ordinary
filename. A possible security issue is allowing this method to be
called with file='../../mutalyzer.conf' for example.
The url routing currently makes sure to only call this with filenames
of the form \d+.
""" """
file = 'Results_%s.txt' % result file = 'Results_%s.txt' % result
handle = open(os.path.join(C.Scheduler.resultsDir, file)) handle = open(os.path.join(C.Scheduler.resultsDir, file))
...@@ -1015,9 +1048,9 @@ class Documentation: ...@@ -1015,9 +1048,9 @@ class Documentation:
@todo: Use configuration value for .xsl location. @todo: Use configuration value for .xsl location.
@todo: Cache this transformation. @todo: Cache this transformation.
""" """
url = web.ctx.homedomain + web.ctx.homepath + '/services' url = web.ctx.homedomain + web.ctx.homepath + WEBSERVICE_LOCATION
wsdl_handle = StringIO(webservice.soap_application.get_wsdl(url)) wsdl_handle = StringIO(webservice.soap_application.get_wsdl(url))
xsl_handle = open('templates/wsdl-viewer.xsl', 'r') xsl_handle = open(WSDL_VIEWER, 'r')
wsdl_doc = etree.parse(wsdl_handle) wsdl_doc = etree.parse(wsdl_handle)
xsl_doc = etree.parse(xsl_handle) xsl_doc = etree.parse(xsl_handle)
transform = etree.XSLT(xsl_doc) transform = etree.XSLT(xsl_doc)
...@@ -1038,6 +1071,10 @@ class Static: ...@@ -1038,6 +1071,10 @@ class Static:
exist. Special case is a page of None, having the same exist. Special case is a page of None, having the same
effect as 'index'. effect as 'index'.
@type page: string @type page: string
Be careful to only call this method with an argument that is a simple
template name. For example, make sure this is not called with page
value '../forbidden'. This check is implemented in the url routing.
""" """
if not page: if not page:
page = 'index' page = 'index'
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
Compilation instructions: Compilation instructions:
wsdl '<tal tal:replace = "path"></tal>/services/?wsdl' wsdl '<tal tal:replace = "path"></tal>/services/?wsdl'
gmcs /target:library MutalyzerService.cs -r:System.Web.Services gmcs /target:library Mutalyzer.cs -r:System.Web.Services
gmcs /r:MutalyzerService.dll client-mono.cs gmcs /r:Mutalyzer.dll client-mono.cs
Usage: Usage:
...@@ -12,7 +12,7 @@ Usage: ...@@ -12,7 +12,7 @@ Usage:
using System; using System;
class Mutalyzer { class MutalyzerClient {
public static void Main(string [] args) { public static void Main(string [] args) {
...@@ -21,7 +21,7 @@ class Mutalyzer { ...@@ -21,7 +21,7 @@ class Mutalyzer {
Console.WriteLine("Checking " + c.variant); Console.WriteLine("Checking " + c.variant);
MutalyzerService mutalyzer = new MutalyzerService(); Mutalyzer mutalyzer = new Mutalyzer();
checkSyntaxResponse result = mutalyzer.checkSyntax(c); checkSyntaxResponse result = mutalyzer.checkSyntax(c);
......
...@@ -553,7 +553,7 @@ ...@@ -553,7 +553,7 @@
</td> </td>
<td align="middle"> <td align="middle">
<img src = "base/images/LUMC_24x24.png" align = "middle"> <img src = "base/images/LUMC_24x24.png" align = "middle">
&nbsp; &copy; 2010 <a href = "http://www.lumc.nl">LUMC</a> &nbsp; &copy; 2007-2011 <a href = "http://www.lumc.nl">LUMC</a>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;
</td> </td>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment