Skip to end of metadata
Go to start of metadata

See how the leave request scenario can be realized in an Android App leveraging SAP NetWeaver Gateway and the OAuth 2.0 SAML Bearer Assertion Flow. For this purpose we created a demo Android App based on the SAP NetWeaver Gateway Android Toolkit.

Table of Contents:

The Scenario

Configuration Guide for this scenario

To get this scenario running several configuration steps have been performed. Click on the links below to see the step-by-step descriptions for the various components involved.

Configuration Step

Tools used

OData Service Enablement
OAuth 2.0 enabling of the approval service, OAuth 2.0 Scope creation and assignment

SAP NetWeaver Gateway Transaction /IWFND/MAINT_SERVICE

Trust Relationship to the Security Token Service (STS)
Configure the Gateway System to trust SAML Bearer assertions issued by the STS

Transaction SAML2

Security Token Service Setup
Registration of the SAP NW Gateway System in order for the STS to be able to issue SAML Assertions for it

Security Token Service Configuration

OAuth 2.0 Client Registration
Registration of the OAuth 2.0 client “LEAVEAPP”, which is the client the Android App is using to make calls on behalf of the resource owner user

Transaction SOAUTH2

Resource Owner Authorizations
Assignment of authority object S_SCOPE next to the manager and employee users' usual permissions

Transaction PFCG

Examine the Source Code

Leave a comment on the page or send a private message to one of the authors of the page in order to receive the source code. 

The app is developed using the SAP NetWeaver Gateway Android Toolkit which offers a lot of useful features like asynchronous messaging, CSRF protection handling and UI as well as Proxy generation for a given OData service.

Based on an Android starter application project generated with the toolkit the following features have been implemented

  • A delegate class taking care of the OAuth 2.0 and SAML handling, which ist called prior to the OData service request (see class OAuth2Delegate)
  • A basic OAuth 2.0 Access token storage (see class OAuth2AndroidTokenHandler)
  • The CSRF handling and its delegate class was adapted so that OAuth 2.0 access tokens are used to fetch CSRF tokens (see class
    SDMConnectivityHelper.getCSRFData())
  • The details activity was enhanced with a button to approve leave requests.
  • OAuth 2.0 support for the different activities (login, list, detail activity), including automatic redirect to login screen if access token has become invalid.

The sources of the App can be found on SDN Code Exchange. Click here to download the eclipse project .

Here’s a description of the contents of the various java packages.

Package

Content

com.sap.security.oa2

The classes that are performing the STS and OAuth 2.0 Token Endpoint calls

com.sap.security.oa2.android

Access Token & Settings storage (currently unencrypted)
Delegate class OAuth2Delegate

com.sap.security.oa2.demo

The various activity screens (login activity, list activity, detail view activity)
Leave request approval service OData proxies (as generated by the toolkit, unmodified)

com.sap.security.oa2.demo.proxy.helpers

Modified SDMConnectivityHelper class (provided by the Gateway Android toolkit)

If you want to be able to build the App you additionally have to install the Android Developer Tools (ADT) plugin for Eclipse.

This App is for demonstrative purposes only. It’s not meant to be directly used in a productive scenario. In a productive scenario it’s inevitable to store the access token in encrypted form. Furthermore a more sophisticated access token retrieval from storage should be implemented.

Message Flows

See the http messages the App exchanges with the Security Token Service and the SAP NetWeaver Gateway system.

1. Security Token Request

After the logon button is pressed the app will attempt to get a SAML Assertion from the Security Token Service. For this sake it’s using the WS-Trust protocol.

POST https://gatewayhe.sap.de:1443/sts/username HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Host: gatewayhe.sap.de:1443
Content-Length: 1953
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
	<s:Header>
		<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
		<a:MessageID>urn:uuid:021a7d99-6b05-4089-adc3-995460c97bc6</a:MessageID>
		<a:ReplyTo>
			<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
		</a:ReplyTo>
		<a:To s:mustUnderstand="1">https://gatewayhe.sap.de:1443/sts/username</a:To>
		<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
			<u:Timestamp u:Id="_0">
				<u:Created>2013-03-14T07:55:55Z</u:Created>
				<u:Expires>2013-03-14T08:01:55Z</u:Expires>
			</u:Timestamp>
			<o:UsernameToken u:Id="uuid-322dfa37-981c-4642-8b1a-2dd1e02d26b7-1">
				<o:Username>Bob</o:Username>
				<o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Boss123</o:Password>
			</o:UsernameToken>
		</o:Security>
	</s:Header>
	<s:Body>
		<trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
			<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
				<a:EndpointReference>
					<a:Address>https://gatewayhe.sap.de:1443/sap/bc/sec/oauth2/token</a:Address>
				</a:EndpointReference>
			</wsp:AppliesTo>
			<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
			<i:RequestDisplayToken xmlns:i="http://schemas.xmlsoap.org/ws/2005/05/identity"/>
			<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
			<trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
		</trust:RequestSecurityToken>
	</s:Body>
</s:Envelope>

2. Security Token Response

After a successful authentication at the Security Token Service a SAML assertion will be sent back inside a WS-Trust Security Token Response.

HTTP/1.1 200 OK
Date: Thu, 14 Mar 2013 08:15:39 GMT
Content-Length: 5987
Content-Type: application/soap+xml; charset=utf-8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
	<s:Header>
		<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal</a:Action>
		<a:RelatesTo>urn:uuid:021a7d99-6b05-4089-adc3-995460c97bc6</a:RelatesTo>
		<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
			<u:Timestamp u:Id="_0">
				<u:Created>2013-03-14T07:57:08.633Z</u:Created>
				<u:Expires>2013-03-14T08:02:08.633Z</u:Expires>
			</u:Timestamp>
		</o:Security>
	</s:Header>
	<s:Body>
		<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
			<trust:RequestSecurityTokenResponse>
				<trust:Lifetime>
					<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-03-14T07:57:08.620Z</wsu:Created>
					<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-03-14T08:57:08.620Z</wsu:Expires>
				</trust:Lifetime>
				<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
					<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
						<wsa:Address>https://gatewayhe.sap.de:1443/sap/bc/sec/oauth2/token</wsa:Address>
					</wsa:EndpointReference>
				</wsp:AppliesTo>
				<trust:RequestedSecurityToken>
					<Assertion ID="_86845c5a-eaf8-4a75-a921-28456232cc86" IssueInstant="2013-03-14T07:57:08.622Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
						<Issuer>http://gatewayhe.sap.de/sts</Issuer>
						<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
							<ds:SignedInfo>
								<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
								<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
								<ds:Reference URI="#_86845c5a-eaf8-4a75-a921-28456232cc86">
									<ds:Transforms>
										<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
										<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
									</ds:Transforms>
									<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
									<ds:DigestValue>ik71oJVoUd3Se915LeTu/vIXD8A=</ds:DigestValue>
								</ds:Reference>
							</ds:SignedInfo>
							<ds:SignatureValue>SJQJ...</ds:SignatureValue>
							<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
								<ds:X509Data>
									<ds:X509Certificate>MII...
								</ds:X509Data>
							</KeyInfo>
						</ds:Signature>
						<Subject>
							<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Bob</NameID>
							<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
								<SubjectConfirmationData NotOnOrAfter="2013-03-14T08:02:08.622Z"/>
							</SubjectConfirmation>
						</Subject>
						<Conditions NotBefore="2013-03-14T07:57:08.620Z" NotOnOrAfter="2013-03-14T08:57:08.620Z">
							<AudienceRestriction>
								<Audience>https://gatewayhe.sap.de:1443/sap/bc/sec/oauth2/token</Audience>
							</AudienceRestriction>
						</Conditions>
						<AuthnStatement AuthnInstant="2013-03-14T07:57:08.559Z">
							<AuthnContext>
								<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>
							</AuthnContext>
						</AuthnStatement>
					</Assertion>
				</trust:RequestedSecurityToken>
				<trust:RequestedAttachedReference>
					<SecurityTokenReference b:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:b="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
						<KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_86845c5a-eaf8-4a75-a921-28456232cc86</KeyIdentifier>
					</SecurityTokenReference>
				</trust:RequestedAttachedReference>
				<trust:RequestedUnattachedReference>
					<SecurityTokenReference b:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:b="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
						<KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_86845c5a-eaf8-4a75-a921-28456232cc86</KeyIdentifier>
					</SecurityTokenReference>
				</trust:RequestedUnattachedReference>
				<trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
				<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
				<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
			</trust:RequestSecurityTokenResponse>
		</trust:RequestSecurityTokenResponseCollection>
	</s:Body>
</s:Envelope>

3. Access Token Request

Having received a SAML assertion which identifies the resource owner user an OAuth 2.0 access token will be requested directly at the Gateway system where the OData service is hosted on.

POST https://gatewayhe.sap.de:1443/sap/bc/sec/oauth2/token HTTP/1.1
Authorization: Basic TE...
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Host: gatewayhe.sap.de:1443
Content-Length: 4534

client_id=LEAVEAPP&scope=ZLEAVEREQUESTAPPR2_0001&grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer&assertion=PEFzc2Vy...

4. Access Token Response

After successful authentication of the OAuth 2.0 client (the App in this case) and the resource owner an access token is sent back. This access token indicates that it's valid for OData service ZLEAVEREQUESTAPPR_0001 (meaning approval service in first version). The access token is now used for all proceeding requests. The initial roundtrip to the Security Token Service and the OAuth 2.0 Token Endpoint at the Gateway system is not needed anymore as long as the access token is still valid. Therefore in a productive scenario it's recommended to have a long access token validity.

HTTP/1.1 200 OK
Date: Thu, 14 Mar 2013 08:15:40 GMT
Server: SAP NetWeaver Application Server / ABAP 731
content-type: application/json; charset=utf-8
content-length: 142
cache-control: no-store
pragma: no-cache

{ "access_token":"AFBWmAGzHtKjj-tfpRXSiMPdKUDqd88SFxrzwcxRGuOIdmH7","token_type":"Bearer","expires_in":"600","scope":"ZLEAVEREQUESTAPPR_0001"}

5. OData Service Request

The access token will now be used in the HTTP Bearer authorization header to access the service.

GET https://gatewayhe.sap.de:1443/sap/opu/odata/sap/zleaverequestappr/?sap-client=001 HTTP/1.1
Authorization: Bearer AFBWmAGzHtKjj-tfpRXSiMPdKUDqd88SFxrzwcxRGuOIdmH7
Host: gatewayhe.sap.de:1443

When performing change operations (HTTP POST, PUT, DELETE), prior to the OData service access an XSRF (CSRF) token needs to be fetched. This can be done using the OAuth 2.0 access token. The SAP NetWeaver Gateway Android Toolkit provides the CSRF handling in a so called delegate classes. See class SDMConnectivityHelper.getCSRFData() as starting point.

6. OData Service Response

HTTP/1.1 200 OK
Date: Thu, 14 Mar 2013 08:15:40 GMT
Server: SAP NetWeaver Application Server / ABAP 731
content-type: application/atomsvc+xml
content-length: 877
dataserviceversion: 2.0
set-cookie: sap-usercontext=sap-client=001; path=/

<?xml version="1.0" encoding="utf-8"?><app:service xml:lang="en" xml:base="https://gatewayhe.sap.de:1443/sap/opu/odata/sap/zleaverequestappr/" ...

2 Comments

  1. Former Member

    Hi,

     

    We are trying to call a few oData POST services from a non sap Web UI. Can we please get some help on this.

     

    Thanks & Regards

    Nidhi

  2. Hello,

    If I go and check who has approved the leave request. Which user id gets updated in the table. Is it 'LEAVAPP' or Manager's user id (In this example Bob).