w eb s erv ices a n d s o a p - university of california ... · w eb s erv ices a n d s o a p ......

40
Web Services and SOAP Mark Slater CMPS 183 - Hypermedia and the Web May 19, 2005 Department of Computer Science Baskin School of Engineering UC Santa Cruz

Upload: vukhanh

Post on 29-May-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Web Services and SOAPMark Slater

CMPS 183 - Hypermedia and the WebMay 19, 2005

Department of Computer ScienceBaskin School of Engineering

UC Santa Cruz

Web Services

Programming Web Services with SOAP,James Snell et. al., O’Reilly, January 2002

“... a network accessible interface to application functionality, built using standard Internet technology”

Web-based abstraction layer between application client and application code

Web Services in History

CORBA - Common Object Request Broker Architecture

Platform and language independent object-oriented architecture

JAVA - Remote Method Invocation

JavaScript - 1996 by Netscape

Flash - 1996 by Macromedia

Modern Web Services

XML-RPC

Remote Procedure Call using XML messages in the body of an HTTP POST.

Invented by Dave Winer of Userland software

Non-standard

Example XML-RPCPOST /RPC2 HTTP/1.0User-Agent: Frontier/5.1.2 (WinNT)Host: betty.userland.comContent-Type: text/xmlContent-length: 181

<?xml version="1.0"?><methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params></methodCall>

Source: http://www.xmlrpc.org/spec

XML-RPC

Types: int (i4), boolean, string, double, dateTime, base64, struct

Example Struct:<struct> <member> <name>lowerBound</name> <value><i4>18</i4></value> </member> <member> <name>upperBound</name> <value><i4>139</i4></value> </member></struct>

SOAP

Simple Object Access Protocol

“Competitor” to XML-RPC

Standardized by W3C

Now the de-facto standard for Web Services

Remote Procedure Call style

Electronic Document Interface (EDI) style

SOAP Adoption

Adopted by Microsoft for inter-application communication in .NET.

Built into C#

J2EE 1.4 requires JAX-RPC (Java implementation of SOAP)

Apple’s MacOS X 10.3 - AppleScript, Carbon, Cocoa

SOAP Adoption

Also available in other languages:

PHP 4 and 5

Perl

Python

etc.

(Very) Basic SOAP Architecture

ApplicationCode

ClientCode

SOAP over

HTTPJava-specificcalls and datatypes

PHP-specificcalls and datatypes

SOAP Messages

Envelope

Zero or One Header

One Body

Any number of well-formed XML elements

Must be namespace qualified

Sample EDI-Style<s:Envelope xmlns:s=”http://www.w3.org/2001/06/soap-envelope”> <s:Header> <m:transaction xmlns:m=”soap-transaction” s:mustUnderstand=”true”> <transactionID>999</transactionID> </m:transaction> </s:Header> <s:Body> <u:grade xmlns:u=”http://www.ucsc.edu/soap/grades”> <u:year>2005</u:year> <u:quarter>Winter</u:quarter> <u:sid>W0001234</u:sid> <u:callnum>93819393</u:callnum> <u:grade>B+</u:grade> </u:grade> </s:Body></s:Envelope>

Sample RPC-Style<s:Envelope xmlns:s=”http://www.w3.org/2001/06/soap-envelope”> <s:Header> <m:transaction xmlns:m=”soap-transaction” s:mustUnderstand=”true”> <transactionID>999</transactionID> </m:transaction> </s:Header> <s:Body> <g:getGrade xmlns:u=”urn:gradeService”> <year xsi:type=”xsd:int”>2005</year> <quarter xsi:type=”xsd:string”>Winter</quarter> <sid xsi:type=”xsd:string”>W0001234</sid> <callnum xsi:type=”xsd:int”>93819393</callnum> </g:getGrade> </s:Body></s:Envelope>

String getGrade( int year, String quarter, String sid, int callnum );

Sample RPC-Style<s:Envelope xmlns:s=”http://www.w3.org/2001/06/soap-envelope”> <s:Body> <g:getGradeResponse xmlns:u=”urn:gradeService”> <grade xsi:type=”xsd:string”>B+</grade> </g:getGradeResponse> </s:Body></s:Envelope>

Structs

Arrays

RPC-Style Structs And Arrays

<student> <sid>W0009999</sid> <firstName>Jane</firstName> <familyName>Doe</familyName> ...</student>

<students> <student sid=”W0001234”/> <student sid=”W0009999”/></students>

RPC-Style Arrays and Binary

Double dimensional arrays, bounded and unbounded

Partially transmitted arrays with offset

Sparse arrays transmit only non-null positions

Position can be specified as null

Base64 encoding for binary transfer (JPEG, etc.)

RPC-Style Multi-Reference

<classes> <class> <enrollment> <student href=”#student-1”/> ... </enrollment> .... </class> <class> <enrollment> <student href=”#student-1”/> ... </enrollment> .... </class></classes><students> <student id=”student-1”> .... </student></students>

When things go wrong

What can go wrong

Network / Communications error

Incorrect target address

Service unavailable

Illegal service request or parameter

SOAP Faults returned for service-level errors

Standard SOAP Faults

VersionMismatch - between client and service SOAP envelope namespaces

MustUnderstand - required header block not understood

Server - Unknown error not directly related to message (Database)

Client - Problem with the message

Custom SOAP Faults

Defined by the service

Must be namespace-qualified

Use with caution since not all SOAP processors handle these gracefully

Extending standard faults is preferred

Example SOAP Fault<s:Envelope xmlns:s=”http://www.w3.org/2001/06/soap-envelope”> <s:Header> <f:Misunderstood qname=”abc:transaction” xmlns:=”soap-transactions” /> </s:Header> <s:Body> <s:Fault> <faultcode>MustUnderstand</faultcode> <faultstring>Header(s) not understood</faultstring> <faultactor>http://www.ucsc.edu</faultactor> </s:Fault> </s:Body></s:Envelope>

Talking to SOAP

SOAP describes the structure of the message, not the content

How do you pass a person’s name?

or

<student> <firstName>Jane</firstName> <familyName>Doe</familyName> ...</student>

<student> <name>Doe, Jane</name> ...</student>

Describing a SOAP Service

Web Service Description Language (WSDL)

Everything you need to know when interacting with that service

Sometimes generated on-the-fly, more efficient when static

Example WSDL<wsdl:definitions xmlns:typens="http://soap.amazon.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://soap.amazon.com" name="AmazonSearch"> <wsdl:types> <xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soap.amazon.com"> <xsd:complexType name="ProductLineArray"> <xsd:complexContent> <xsd:restriction base="soapenc:Array"> <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="typens:ProductLine[]"/> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="ProductLine"> <xsd:all> <xsd:element name="Mode" type="xsd:string" minOccurs="0"/> <xsd:element name="ProductInfo" type="typens:ProductInfo" minOccurs="0"/> </xsd:all> </xsd:complexType> ...

Example WSDL <message name="RemoveShoppingCartItemsRequest"> <part name="RemoveShoppingCartItemsRequest" type="typens:RemoveShoppingCartItemsRequest"/> </message> <message name="ModifyShoppingCartItemsRequest"> <part name="ModifyShoppingCartItemsRequest" type="typens:ModifyShoppingCartItemsRequest"/> </message> <message name="ShoppingCartResponse"> <part name="ShoppingCart" type="typens:ShoppingCart"/> </message> <portType name="AmazonSearchPort"> <!-- Port for Amazon Web APIs --> <operation name="KeywordSearchRequest"> <input message="typens:KeywordSearchRequest"/> <output message="typens:KeywordSearchResponse"/> </operation> <operation name="PowerSearchRequest"> <input message="typens:PowerSearchRequest"/> <output message="typens:PowerSearchResponse"/> </operation> <operation name="BrowseNodeSearchRequest"> <input message="typens:BrowseNodeSearchRequest"/> <output message="typens:BrowseNodeSearchResponse"/> </operation>

Example WSDL </portType> <binding name="AmazonSearchBinding" type="typens:AmazonSearchPort"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <!-- Binding for Amazon Web APIs - RPC, SOAP over HTTP --> <operation name="ModifyShoppingCartItemsRequest"> <soap:operation soapAction="http://soap.amazon.com"/> <input> <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://soap.amazon.com"/> </input> <output> <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://soap.amazon.com"/> </output> </operation> </binding> <service name="AmazonSearchService"> <!-- Endpoint for Amazon Web APIs --> <port name="AmazonSearchPort" binding="typens:AmazonSearchBinding"> <soap:address location="http://soap.amazon.com/onca/soap2"/> </port> </service> <!--Shopping Cart--></wsdl:definitions>

Amazon Web Services

Google Web Services

Example WSDL

Registering Web Services

Similar to P2P tracker ideas

Web Services are registered with Universal Description, Discovery, and Integration (UDDI) registries

Complex and frequently overkill

WS-Inspection is a lightweight method of describing web services in a given site

Web Services Security

No good standards yet (that I know of)

Use HTTPS for point-to-point encryption

XML Digital Signatures and XML Encryption standards may provide the necessary features

Compatibility

Not all implementations are compatible

Apache Axis 1.1 vs. Apache Axis 1.2

Section 5 Encoding

Microsoft .NET

Sample Web Servicepackage edu.ucsc.whisper.rpc;

import java.rmi.Remote;import java.rmi.RemoteException;

public interface RemoteUserService extends Remote{ boolean confirmCredentials( String username, String password ) throws RemoteException; boolean changePassword( String username, String password, String newPassword ) throws RemoteException;}

Sample Web Servicepackage edu.ucsc.whisper.rpc;

import org.springframework.remoting.jaxrpc.ServletEndpointSupport;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import edu.ucsc.whisper.core.User;import edu.ucsc.whisper.core.UserManager;import edu.ucsc.whisper.service.UserService;

/** * Provides a Web Services client interface to User-related services within whisper. */public class JaxRpcUserService extends ServletEndpointSupport implements UserService, RemoteUserService{ /** The user manager that provides access to user data in the system. */ private UserManager userManager; /** Logger for this class and subclasses. */ private Log logger = LogFactory.getLog( getClass() ); /** * Return the logger. * * @return The logger for this class and its subclasses. */ protected final Log getLogger() { return( logger ); }

Sample Web Service /** * Initialize the service. This function has access to Spring Framework contexts. */ protected final void onInit() { setUserManager( (UserManager) getWebApplicationContext().getBean( "userManager" ) ); } /** * Set the user manager that will perform backend tasks for the service provider. * * @param manager The UserManager instance to use. */ public final void setUserManager( final UserManager manager ) { userManager = manager; }

Sample Web Service /** * Confirm a user's credentials by matching the submitted (encrypted) password to the * (encrypted) password stored for that user. * * @param username The user whose credentials are being examined. * @param password The encrypted password being examined. * * @return TRUE if a user with the specified username exists and the encrypted password for * user matches the specified encrypted password, FALSE if there is no match, either * parameter is invalid (null or only whitespace), or no user by that name can be found. */ public final boolean confirmCredentials( final String username, final String password ) { boolean credentialsValid = false; if( ( username != null ) && ( username.trim().length() > 0 ) && ( password != null ) && ( password.trim().length() > 0 ) ) { User u = userManager.getUser( username ); getLogger().info( "Confirming credentials: username=" + username + ", password=" + password ); // To verify the credentials, the user must be found, have a password equal to the // submitted password, and the account must be enabled. credentialsValid = ( u != null ) && u.getPassword().equals( password ) && u.isEnabled(); } return( credentialsValid ); }

Sample Web Service /** * Change a user's password. * * @param username The user's username. * @param password The user's current hashed password. * @param newPassword The user's new hashed password. * * @return TRUE if the password was successfuly changed, and FALSE if the user's current * credentials could not be verified or if the new password was invalid (null, empty * string, etc.). */ public final boolean changePassword( final String username, final String password, final String newPassword ) { boolean success = false; if( ( username != null ) && ( username.trim().length() > 0 ) && ( password != null ) && ( password.trim().length() > 0 ) && ( newPassword != null ) && ( newPassword.trim().length() > 0 ) ) { User u = userManager.getUser( username ); if( ( u != null ) && u.getPassword().equals( password ) ) { u.setPassword( newPassword ); success = true; userManager.storeUser( u ); } } return( success ); } }

Sample PHP Client<?php

class User{ private $username = ""; private $password = ""; public function __construct( $username, $password ) { $this->username = $username; $this->password = $password; } public function getUsername() { return( $this->username ); } public function getPassword() { return( $this->password ); }

Sample PHP Client public function validateUser() { $userService = new SoapClient( $_SESSION[ 'config' ]->getServerBaseURL() . "ws/UserService?wsdl", array( 'trace' => 1 ) ); $confirmed = false; try { $confirmed = $userService->confirmCredentials( $this->username, $this->password ); } catch( Exception $e ) { echo "caught exception<br>\n"; print_r( $e ); echo "<p>\n"; echo "Request :<br>", htmlspecialchars($userService->__getLastRequest()), "<p>"; echo "Response :<br>", htmlspecialchars($userService->__getLastResponse()), "<p>"; } return( $confirmed ); }

Sample PHP Client public function changePassword( $newPassword ) { $confirmed = false; $userService = new SoapClient( $_SESSION[ 'config' ]->getServerBaseURL() . "ws/UserService?wsdl", array( 'trace' => 1 ) ); try { $confirmed = $userService->changePassword( $this->username, $this->password, $newPassword ); if( $confirmed === true ) { $this->password = $newPassword; } } catch( Exception $e ) { echo "caught exception<br>\n"; print_r( $e ); echo "<p>\n"; echo "Request :<br>", htmlspecialchars($userService->__getLastRequest()), "<p>"; echo "Response :<br>", htmlspecialchars($userService->__getLastResponse()), "<p>"; } return( $confirmed ); }}?>

Web Service Config<?xml version="1.0" encoding="UTF-8"?><deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <globalConfiguration> <parameter name="sendXsiTypes" value="true"/> <parameter name="sendMultiRefs" value="true"/> <parameter name="sendXMLDeclaration" value="true"/> <parameter name="axis.sendMinimizedElements" value="true"/> <parameter name="axis.development.system" value="true"/> </globalConfiguration>

<handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/> <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> <!-- The soap monitor service should be commented out for production systems. --> <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler"> <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/> <parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/> <parameter name="serviceName" value="SOAPMonitorService"/> <parameter name="portName" value="5001"/> </handler> <service name="SOAPMonitorService" provider="java:RPC"> <parameter name="allowedMethods" value="publishMessage" /> <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/> <parameter name="scope" value="Application"/> </service>

Web Service Config <service name="UserService" provider="java:RPC" style="RPC"> <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="edu.ucsc.whisper.rpc.JaxRpcUserService"/> </service> <transport name="http"> <requestFlow> <handler type="URLMapper"/> <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/> </requestFlow> </transport> <transport name="https"> <requestFlow> <handler type="URLMapper"/> <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/> </requestFlow> </transport> <transport name="local"> <responseFlow> <handler type="LocalResponder"/> </responseFlow> </transport></deployment>