I'm having an issue correctly interfacing with a SOAP API running on Axis2:
What happens is I should call the login method with two arguments (loginName and password) and it returns an authentication token that I will use for subsequent interaction.
#!/usr/bin/python
from SOAPpy import SOAPProxy
s_user = 'Administrator'
s_pass = 'securityThroughObscurity'
s_host = '192.168.76.130:8998'
namespace = 'http://bcc.inc.com/IncSecurity'
url = 'http://' + s_host + '/axis2/services/IncSecurityService'
DHCPServ = SOAPProxy(url, namespace)
DHCPServ.config.dumpSOAPOut = 1
DHCPServ.config.dumpSOAPIn = 1
DHCPResp = DHCPServ.login(loginName=s_user, password=s_pass)
The Axis2 server on the other side returns an XML error stating Data element of the OM Node is NULL. Looking at the Axis2 logs, I see the error is adb_login.c(383) non nillable or minOuccrs != 0 element loginName missing
I then packet captured the login XML from a known working Java client versus the XML from this client and these are the differences between the two:
SOAPpy:
<ns1:login xmlns:ns1="http://bcc.inc.com/IncSecurity" SOAP-ENC:root="1">
<password xsi:type="xsd:string">securityThroughObscurity</password>
<loginName xsi:type="xsd:string">Administrator</loginName>
</ns1:login>
Java:
<ns2:login xmlns:ns2="http://bcc.inc.com/IncSecurity">
<ns2:loginName>Administrator</ns2:loginName>
<ns2:password>securityThroughObscurity</ns2:password>
</ns2:login>
So this means that for some reason (probably related to my lack of knowledge in Python and SOAPpy) the namespace is not being applied to the variables being used in the login method, so by all accounts they don't actually exist and the error is warranted.
Also, it seems to be flipping the variables around and putting the password before loginName but I don't think that matters much.
What am I doing wrong?
Looks like it's a known bug in SOAPPy, someone has suggested a simple patch: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=523083
Alternately (assuming you have access to the service WSDL), SOAPPy lets you specify a WSDL instead of just a namespace. This looks like it will provide better namespace information to the envelope generation code. http://diveintopython.net/soap_web_services/introspection.html
Finally, if SOAPPy just isn't working for you, try Suds (it's better documented than SOAPPy).
from suds.client import Client
from suds.wsse import *
client = Client(WSDL_LOCATION)
guid = client.service.someFunctionName("a string argument", 42)
Good luck!
Related
I have an XML/WCF API I need to implement something against. The API client library is only provided as c# in Windows and our company does not do either c# or Windows. I am now experimenting with Python and zeep. The api is Symmetry access control system API if anyone is interested.
I can connect to the server and read the wsdl structure. This works:
URL='https://localhost/smsXMLWebService/SMSXMLWebService.svc?singleWsdl'
URL2='https://localhost/smsXMLWebService/smsXMLWebService.svc'
session = Session()
session.verify = False
transport = Transport(session=session)
self.client = zeep.Client(URL, transport=transport)
self.service = self.client.create_service('{http://tempuri.org/}WSHttpBinding_ISMSXMLWebService', URL2)
Now everything from that point forward will require login to the platform. In the example c# code this is done as follows:
G4TAPI = new SMSXMLWebServiceClient();
G4TAPI.ClientCredentials.UserName.UserName = txtUserName.Text
G4TAPI.ClientCredentials.UserName.Password = txtPassword.Text.ToLower();
G4TAPI.G4TLogin();
My self.service has now G4TLogin() call and it seems to attempt to connect when I wireshark the traffic. But how do I set the username and password as they are not given as parameters to G4TLogin() method?
This does not work:
self.service.ClientCredentials.UserName.UserName = "api"
This is very much out of my comfort zone and I may be using incorrect terminology here. Any ideas?
The error message is
AttributeError: Service has no operation 'ClientCredentials'
When using Zeep make sure to study the namespaces in WSDL URL, using
python -mzeep "YourWsdlUrlGoesHere"
Get the parameters and make a Python dictionary from them (in my case facing C#, including username and password in the dictionary) note that one might need to make nested dictionary like in my case.
from requests import Session
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
from zeep import Client
from zeep.transports import Transport
request = { "Credential":{"Username": "yourusername",
"Password": "yourpassword"},
"RN": "150147119"
}
session = Session()
client = Client('http://your url and wsdl../Invoice.svc?Wsdl',transport=Transport(session=session))
r = client.service.NameOfYourService(request)
print(r)
Do not pass user and password in Zeep formal format. Passing the dictionary worked for me.
In my case the WSDL suggested user and password be in credential and a string be passed in RN and finally all be passed in a one variable.
So I have seen SOAP client programs with namespace and url for python
and using uri and proxy for perl such as below
python soap client:
#!/usr/bin/python
import sys
from SOAPpy import SOAPProxy
option = sys.argv[1]
serverUrl='http://localhost:9000'
namespace='urn:/Date'
server = SOAPProxy(serverUrl, namespace)
response = server.dateInfo(option)
# read out the response
if (response == None):
print "Call returned error."
sys.exit(1)
print "Currently server date and time is " + response
perl soap client:
#!perl -w
use SOAP::Lite;
$soap_response = SOAP::Lite
-> uri('http://www.soaplite.com/Demo')
-> proxy('http://services.soaplite.com/hibye.cgi')
-> languages();
#res = $soap_response->paramsout;
$res = $soap_response->result;
print "Result is $res, outparams are #res\n";
Now here in first, namespace is urn:/Date
and in second program uri is http://www.soaplite.com/Demo.
I know that uri and namespace are words used to represent the same i.e. namespace used by SOAP to register a service.
My question is that whether the format used to name it
i.e. urn:... or http://... mandatory
or can I simply use something like testwebservice to register web service
The namespace name is an absolute IRI. (An IRI is basically an URI with support for non-ASCII characters.) Any absolute IRI. The scheme (http, urn, etc) doesn't matter. It can't be testwebservice since that's not a valid absolute IRI (or URI).
The namespace name is only used for identification purposes. It isn't used for resource retrieval, so using an HTTP IRI that would return 404 is perfectly fine.
I am trying to create a very simple Python script to download the contents of an internal service at my company that sits within our firewall and authenticates using kerberos.
When I installed the requests_kerberos module I first edited the import kerberos in it to use import kerberos_sspi as kerberos instead after having installed the kerberos_sspi module.
Thus I have the following Python script
import requests
from requests_kerberos import HTTPKerberosAuth
response = requests.get('http://service.internaldomain',auth=HTTPKerberosAuth())
print response
While trying to process the 401 it crashes out with the error.
error: (-2146893053, 'InitializeSecurityContext', 'The specified target is unknown or unreachable')
While looking into seeing if I could do this with curl instead I ran kinit and noticed that it asked me for the password to authorisation with the following prompt:
Password for username#additionalInternalDomain.internaldomain
Thus I wondered if this might be what is causing the issue.
I have tried multiple libraries on python and failed when trying to authenticate from a windows machine.There is no easy way. The Kerberos libraries mainly work on Linux. The workarounds for Windows do not work. So what can be the solution to this.
Well... be a Roman while in Rome. Try the windows native libraries from Python.
import sys
import clr
from System.Net.Http import *
myClienthandler = HttpClientHandler()
myClienthandler.UseDefaultCredentials = True
myClient = HttpClient(myClienthandler)
x = myClient.GetStringAsync("putyourURLwithinthequoteshere")
myresult = x.Result
print(myresult)
Note that the this python script will have to run by the user who has access to the URL you are trying to access. By setting UseDefaultCredentials property as True, you are passing the Kerberos tickets for the logged in user.
The server is giving you a 401 challenge - and the client (usually a browser or even curl) provides the credentials in a subsequent call. If you are already logged in at your domain - try forcing a pre-emptive hop, i.e. you’d carry your Kerberos ticket with your call and the server will not give you a 401 challenge:
kerberos_auth = HTTPKerberosAuth(force_preemptive=True)
r = requests.get("http://myhost/DXAPIGraphQL/api/graphql", auth=kerberos_auth)
If the above doesn't help look into the:
principal and hostname_override arguments of the HTTPKerberosAuth class.
I had to connecto to a REST API who's in a keberized environment just now.
After some reading, i came to this (and it worked):
tk = 'long_kerberos_token'
headers = {'Authorization': 'Negotiate' + tk}
r = requests.get(url=PING_URL, headers=headers)
I've been able to finally get python-openid to authenticate a user, but I'm not able to create a sreg.SRegResponse or ax.FetchResponse as they come back as None. This is coming from a Google Apps account and I'm trying to follow the example from https://github.com/openid/python-openid/tree/master/examples/djopenid. I've heard Google's OpenID system can be a little funky and require some tweaks like Retrieve OpenID AX attributes from Google / Yahoo in Rails
response = c.complete(request_args, return_to)
sreg_response = sreg.SRegResponse.fromSuccessResponse(response)
ax_response = ax.FetchResponse.fromSuccessResponse(response)
The response is definitely coming back as a SUCCESS, but I see the following error message, which may be related:
Generated checkid_setup request to https://www.google.com/accounts/o8/ud with assocication AOQobUdVBCrd-GZRcasn9tD-yOUF0Y8pJLAQrYXODqLxUUjN62G1BXR1
Error attempting to use stored discovery information: <openid.consumer.consumer.TypeURIMismatch: Required type http://specs.openid.net/auth/2.0/signon not found in ['http://specs.openid.net/auth/2.0/server', 'http://openid.net/srv/ax/1.0', 'http://specs.openid.net/extensions/ui/1.0/mode/popup', 'http://specs.openid.net/extensions/ui/1.0/icon', 'http://specs.openid.net/extensions/pape/1.0'] for endpoint <openid.consumer.discover.OpenIDServiceEndpoint server_url='https://www.google.com/accounts/o8/ud' claimed_id=None local_id=None canonicalID=None used_yadis=True >>
Attempting discovery to verify endpoint
Performing discovery on https://www.google.com/accounts/o8/id?id=AItOawkKU4uzJV9Q_FGMECNGsbiXG2caISYMyCw
Received id_res response from https://www.google.com/accounts/o8/ud using association AOQobUdVBCrd-GZRcasn9tD-yOUF0Y8pJLAQrYXODqLxUUjN62G1BXR1
Here's my setup.
sreg_request = sreg.SRegRequest(optional=['email', 'nickname'],
required=['dob'])
auth_request.addExtension(sreg_request)
# Add Attribute Exchange request information.
ax_request = ax.FetchRequest()
# XXX - uses myOpenID-compatible schema values, which are
# not those listed at axschema.org.
ax_request.add(ax.AttrInfo('http://schema.openid.net/namePerson',
required=True))
ax_request.add(ax.AttrInfo('http://schema.openid.net/contact/web/default',
required=False, count=ax.UNLIMITED_VALUES))
auth_request.addExtension(ax_request)
I was having problems with Google returning not the schema.openid.net values for AttributeExchange. It was returning None just like you mentioned, and the worst part is that it used to work when I first wrote my OpenID handlers.
Once I switched over to the axschema values in my implementation, it worked like a charm. ex:
URLS = {
'ax_email': 'http://axschema.org/contact/email',
'ax_first': 'http://axschema.org/namePerson/first',
}
...
ax_request = ax.FetchRequest()
ax_request.add(ax.AttrInfo(URLS['ax_email'], required = True))
ax_request.add(ax.AttrInfo(URLS['ax_first'], required = True))
auth_request.addExtension(ax_request)
How can I access 37 signals Highrise's API with Python? Found wrappers for PHP/Ruby, but not Python. I'm writing my own now, anyone have advice on getting over the first hurdle of authentication with Python?
I wrote (am writing, really) a Highrise API wrapper for Python. It uses Python objects for each of the Highrise classes and work a lot like the Django ORM:
>>> from pyrise import *
>>> Highrise.server('my-server')
>>> Highrise.auth('api-key-goes-here')
>>> p = Person()
>>> p.first_name = 'Joe'
>>> p.last_name = 'Schmoe'
>>> p.save()
You can get the source from GitHub: https://github.com/feedmagnet/pyrise
Or install it from PyPI:
$ sudo pip install pyrise
I was just tackling this problem when I stumbled onto your question. Here is what I have hacked together so far. Its not pretty (yet) but it works. I don't know Pycurl and after looking at it for a while I went back to urllib2. Highrise uses Basic Authentication so you don't have to use CURL you can use urllib2. You just have to go through all the Pword Manager steps. The output is a long XML file of either all the companies or the people depending on which URL you insert. If you wanted just one person you could do something like 'http....../people/123.xml' or 'http....../people/123-fname-lname.xml' (like you see in the url when you actually go to a contact in highrise with the .xml added).
import ullib2
PEOPLEurl = 'http://yourcompany.highrisehq.com/people.xml' #get all the people
# or
COMPANYurl = 'http://yourcompany.highrisehq.com/company.xml' #get all companies
token = '12345abcd' #your token
password = 'X'
passmanager = urllib2.HTTPPasswordMgrWithDefaultRealm()
passmanager.add_password(None, PEOPLEurl, token, password)
authhandler = urllib2.HTTPBasicAuthHandler(passmanager)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
page = urllib2.urlopen(PEOPLEurl).read()
print page #this will dump out all the people contacts in highrise
Any feedback or suggestions on this code would be helpful!
See here on how to do basic authentication. Also IIRC urllib supports http://user:password#example.com URLs.
i was just looking to the php code of one of the php API wrappers and i see that they use curl ; so have you looked to pycurl ??
about the authentication here is an example that you can start with (it's not tested)...
import pycurl
def on_receive(data):
# process your data here
pass
def connetion(url, token)
conn = pycurl.Curl()
# Set Token.
conn.setopt(pycurl.USERPWD, "%s:x" % (token,))
# the format TOKEN:x i get it from the PHP wrapper because usually the
# format should be USER:PASSWD so here i think they just use a token as
# a USERname and they set the password to 'x'.
conn.setopt(pycurl.URL, url)
# Set the XML data to POST data.
conn.setopt(pycurl.POSTFIELDS, XML_DATA)
# Add SSL.
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
# Set function that will be called as soon as the data is received.
conn.setopt(pycurl.WRITEFUNCTION, on_receive)
# Perform the data transfer.
conn.perform()
if __name__ == '__main__':
connection("http://yourcompany.highrisehq.com", your_token)