Workday Soap API - User Name/Password - soap

I am trying to call the Workday Integration API. I am able to connect but am getting a invalid username or password message. My question is - where do I put this information? I don't see anything in the wsdl where I can put the user name or password.
Launch_Integration
Thanks for any help!
Warren

For some reason, finding the correct auth method is difficult in the Workday documention, in fact I'm not sure even if it's mentioned anywhere.
If you're using Workday Studio, you may use the Web Service Tester. That will generally allow you customize and form your request and will show you various authentication options.
However if you don't you may use the below envelope for your requests.
In the BODY you need to add the particular WS request you want to use (such as Launch Integration).
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<env:Header>
<wsse:Security env:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>yourusername#yourtenant</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">**YOURPASSWORD***</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</env:Header>
<env:Body>
</env:Body>
</env:Envelope>

I found the following blog post extremely helpful when consuming Workday services. It covers a bunch of the gotchas, including handling the security aspect.
http://dovetailsoftware.com/hr/gcox/2014/06/13/getting-started-workday-web-services-using-c/

I have not used the Integration API but would imagine that it works just like the others that I have used, like Compensation, Benefits, ...
See my answer to this question. You should have an "IntegrationPortClient" object generated in the stub that you can use to authenticate.

If you are using Java, here's the code for handling the credentials. Can't remember where I got it originally, maybe somewhere on the Workday Community website.
Example usage, hrPort and hrService are from class generated from the wsdl:
HumanResourcesPort hrPort = hrService.getHumanResources();
BindingProvider bp = (BindingProvider) hrPort;
WorkdayCredentials.addWorkdayCredentials(bp,
config.getWdIntegrationUsername(),
config.getWdIntegrationPassword());
Here is the class:
/**
*
*/
package com.mycompany.workdayservice.data;
import java.util.List;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.namespace.QName;
import java.util.Set;
/**
* This class creates a handler that will add the WS-Security username and
* password to the to the SOAP request messages for a client side proxy.
*
*/
public class WorkdayCredentials implements SOAPHandler<SOAPMessageContext> {
/** Namespace for the SOAP Envelope. */
private static String SOAPENVNamespace = "http://schemas.xmlsoap.org/soap/envelope/";
/** The prefix that will be used for the SOAP Envelope namespace. */
private static String SOAPENVPrefix = "soapenv";
/** Namespace for the WS-Security SOAP header elements. */
private static String WSSENamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
/** The prefix that will be used for the WS-Security namespace. */
private static String WSSEPrefix = "wsse";
/**
* The WS-Security URI that specifies that the password will be transmitted
* as plain text.
*/
private static String WSSEPasswordText = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
/**
* The user name that will be sent in the WS-Security header on the SOAP
* request message. This is of the form systemid#tenant.
*/
private String username;
/**
* The password that will be sent in the WS-Security header on the SOAP
* request message.
*/
private String password;
/**
* This method created an instance of the WorkdayCredentials class and adds
* it as a handler to the bindingProvider supplied.
*
* #param bindingProvider
* The client stub to which the handler will be added. The most
* convenient way to obtain the required bindingProvvider is to
* call one of the getPort methods on the Service class for the
* Web service and then cast the returned object to a
* BindingProvider.
* #param username
* The id and tenant name for the user. This is of the form
* systemid#tenant.
* #param password
* The password for the system user.
*/
public static void addWorkdayCredentials(BindingProvider bindingProvider,
String username, String password) {
List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
handlerChain.add(new WorkdayCredentials(username, password));
bindingProvider.getBinding().setHandlerChain(handlerChain);
}
/**
* Creates a WorkdayCredentials handler and initialises the member
* variables. In most cases, the addWorkdayCredentials static method should
* be used instead.
*
* #param username
* The id and tenant name for the user. This is of the form
* systemid#tenant.
* #param password
* The password for the system user.
*/
public WorkdayCredentials(String username, String password) {
this.username = username;
this.password = password;
}
/**
* Returns null as this handler doesn't process any Headers, it just adds
* one.
*/
public Set<QName> getHeaders() {
return null;
}
/**
* Adds WS-Security header to request messages.
*/
public boolean handleMessage(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean) smc
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
addWSSecurityHeader(smc, username, password);
}
return true;
}
/**
* Returns true, no action is taken for faults messages.
*/
public boolean handleFault(SOAPMessageContext smc) {
return true;
}
public void close(MessageContext messageContext) {
}
/**
* Adds a WS-Security header containing a UsernameToken to a SOAP message.
*
* #param smc
* The SOAPMessageContent to which the WS-Security header will be
* added.
* #param username
* The WS-Security username.
* #param password
* The WS-Security password.
*
* #throws java.lang.RuntimeException
* This exception will be thrown if a SOAPException occurs when
* modifying the message.
*/
private void addWSSecurityHeader(SOAPMessageContext smc, String username,
String password) throws java.lang.RuntimeException {
try {
// Get the SOAP Header
SOAPMessage message = smc.getMessage();
SOAPHeader header = message.getSOAPHeader();
if (header == null) {
// Create header as it doesn't already exist
message.getSOAPPart().getEnvelope().addHeader();
header = message.getSOAPHeader();
}
// Add WS-Security SOAP Header
SOAPElement heSecurity = header.addChildElement("Security",
WSSEPrefix, WSSENamespace);
heSecurity.addAttribute(message.getSOAPPart().getEnvelope()
.createName("mustUnderstand", SOAPENVPrefix,
SOAPENVNamespace), "1");
// Add the Usernametoken element to the WS-Security Header
SOAPElement heUsernameToken = heSecurity.addChildElement(
"UsernameToken", WSSEPrefix, WSSENamespace);
// Add the Username element to the UsernameToken Element
heUsernameToken.addChildElement("Username", WSSEPrefix,
WSSENamespace).addTextNode(username);
// Add the Password element to the UsernameToken Element
SOAPElement hePassword = heUsernameToken.addChildElement(
"Password", WSSEPrefix, WSSENamespace);
hePassword.addAttribute(message.getSOAPPart().getEnvelope()
.createName("Type"), WSSEPasswordText);
hePassword.addTextNode(password);
} catch (SOAPException e) {
throw new RuntimeException(
"Failed to add WS-Security header to request", e);
}
}
}

Related

Typo3 Fluid extbase- How to execute external controller?

I have 2 different extension. I want to execute second controller (external) inside my first controller
Two different extension 1. Course , 2. Search
class CourseController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* courseRepository
*
* #var \TYPO3\Courses\Domain\Repository\CourseRepository
* #inject
*/
protected $courseRepository = NULL;
/**
* action list
*
* #return void
*/
public function listAction() {
/** I want to access Search extension Controller (f.e searchRepository->listAction() )**/
}
}
class SearchRepository extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* searchRepository
*
* #var \TYPO3\Courses\Domain\Repository\SearchRepository
* #inject
*/
protected $searchRepository = NULL;
/**
* action list
*
* #return void
*/
public function listAction() {
$searches = $this->searchRepository->findAll();
$this->view->assign('searches', $searches);
}
}
tl;dr:
Within a Controller, you usually forward() or redirect() to delegate to a different ControllerAction, e.g. delegate to SearchController::listAction() of 'myExtensionKey':
$this->forward('list', 'Search', 'myExtensionKey');
or
$this->redirect('list', 'Search', 'myExtensionKey');
Long version:
Quote from the MVC documentation of Flow which is quite similar to Extbase MVC:
Often, controllers need to defer execution to other controllers or
actions. For that to happen, TYPO3 Flow supports both, internal and
external redirects:
in an internal redirect which is triggered by forward(), the URI does
not change.
in an external redirect, the browser receives a HTTP
Location header, redirecting him to the new controller. Thus, the URI
changes.
The APIs are:
public void forward(string $actionName, string $controllerName=NULL, string $extensionName=NULL, array $arguments=NULL)
protected void redirect(string $actionName, string $controllerName=NULL, string $extensionName=NULL, array $arguments=NULL, integer $pageUid=NULL, int $delay=0, int $statusCode=303)
The programming API details can be found in the Extbase API

Unable to test the REST API developed with Spring Boot

I am trying to test the REST API created with Spring Boot. Following is the signature of the method:
#RequestMapping(consumes = "multipart/form-data", method = RequestMethod.POST)
public Response<String> upload(#RequestBody CsvUploadModel form) {
Following is the details of Model Object:
private char separator;
private char quoteCharacter;
private String metricName;
private String groupName;
private MultipartFile file;
//getters and setters
I have tried accessing this service using 1. chrome Postman and 2. Simple http POST form. Every time I am getting the error: 415 : Unsupported media type.
EDIT:
Following is the bean configuration for multi part bean:
/**
* Allow file uploads
*
* #return
*/
#Bean
public MultipartConfigElement multipartConfigElement() {
MultiPartConfigFactory factory = new MultiPartConfigFactory();
factory.setMaxFileSize("500MB");
factory.setMaxRequestSize("500MB");
return factory.createMultipartConfig();
}
/**
* Get the multipart resolver
*
* #return
*/
#Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
I tried changing #RequestBody to #RequestParam but it didn't work. Following is the request preview of postman.
POST /dev/wizard/upload HTTP/1.1
Host: localhost:10022
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="metricName"
test
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="separator"
,
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Am I missing anything obvious?
Thanks
#RequestBody CsvUploadModel form
This requires a HttpMessageConverter to be present that can read request payloads of the type multipart/form-data. Unfortunately Spring currently does not provide such a converter. There is a FormHttpMessageConverter, but that can only read simple form data (application/x-www-form-urlencoded).
In order to get your method working you should remove the #RequestBody annotation and add a parameter for the files:
upload(CsvUploadModel form, #RequestParameter(required=false) MultipartFile file)
#RequestBody is not needed for binding form data. You then have to set the file manually:
form.setFile(file);
Maybe there's a third-party converter that supports reading multipart/form-data. Neither do I use nor know any.
Try retrofit
<dependency>
<groupId>com.squareup.retrofit</groupId>
<artifactId>retrofit</artifactId>
<version>1.6.1</version>
</dependency>
.
import retrofit.http.Body;
import retrofit.http.POST;
public interface IRestController {
#POST("/api-name")
public Response api(#Body Request request);
}
.
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import retrofit.RestAdapter;
public class TestRestAPI {
private static final String SERVER = "http://localhost:8080";
private IRestController service = new RestAdapter.Builder()
.setEndpoint(SERVER).build()
.create(IRestController.class);
#Test
public void basicTest(){
Response response = service.api(new Request());
assertNotNull(response);
}
}

GWT polymorphic lists with #ExtraTypes

I have a little problem with a list that contains different types of elements and i would like to see if anyone of you have met the problem before. The issue should be solved with the use of #ExtraTypes, but it is not working for me, so i guess i am not using it correctly. So, the scenario is (bean names are changed for clarity):
GENERAL:
I am using GWT 2.5 with RequestFactory.
SERVER-SIDE:
I have a RootBean that contains, among other stuff, a List <ChildBean>.
This ChildBean contains some primitive attributes.
ChildBean is also extended by a MoreSpecificChildBean that inherits all the parent attributes and adds a few more.
The RootBean gets its list filled up with elements of type ChildBean and MoreSpecificChildBean depending on some logic.
CLIENT-SIDE:
IRootBeanProxy is a ValueProxy with these annotations:
#ProxyFor (value = RootBean.class)
#ExtraTypes ({IMoreSpecificChildBeanProxy.class})
and contains a list
List <IChildBeanProxy> getChildren ();
IChildBeanProxy is a ValueProxy:
#ProxyFor (value=ChildBean)
public interface IChildBeanProxy extends ValueProxy
IMoreSpecificChildBeanProxy is a ValueProxy:
#ProxyFor (value=MoreSpecificChildBean)
public interface IMoreSpecificChildBeanProxy extends IChildBeanProxy
the Request context has a method that returns Request and i added the #ExtraTypes annotation here too:
#Service (value = CompareService.class, locator = SpringServiceLocator.class)
#ExtraTypes ({IChildBeanProxy.class, IMoreSpecificChildBeanProxy.class})
public interface ICompareRequestContext extends RequestContext {
Request <IRootBeanProxy> compare (Integer id1, Integer id2);
Question
Supposedly with those annotations, RF should be aware of the existence of polymorphic inherited classes, but all i get in the client is an IRootBeanProxy with a list of IChildBeanProxy elements. This list includes the MoreSpecificChildBean, but in the shape of a IChildBeanProxy, so that i cannot tell it from the others.
So i am wondering what i am doing wrong, if i am setting the ExtraTypes annotation at the wrong place or something.
Anyone?
Thx for all the help!!
I do the exact same thing for quite a few classes but it will always return me the base type which I can iterate through and test for instanceof if needed. You will probably have to cast the object to the subclass. If you do not add the #ExtraTypes you will know because on the server side you will get a message stating that MoreSpecificChildBean cannot be sent to the client.
I only annotate the service and not the proxy, I ran into some quirks with 2.4 adding #ExtraTypes to the proxy.
/**
* Base proxy that all other metric proxies extend. It is used mainly for it's
* inheritence with the RequestFactory. It's concrete implementation is
* {#link MetricNumber}.
*
* #author chinshaw
*/
#ProxyFor(value = Metric.class, locator = IMetricEntityLocator.class)
public interface MetricProxy extends DatastoreObjectProxy {
/**
* Name of this object in the ui. This will commonly be extended by
* subclasses.
*/
public String NAME = "Generic Metric";
/**
* This is a list of types of outputs that the ui can support. This is
* typically used for listing types of supported Metrics in the operation
* output screen.
*
* #author chinshaw
*/
public enum MetricOutputType {
MetricNumber, MetricString, MetricCollection, MetricStaticChart, MetricDynamicChart
}
/**
* See {#link MetricNumber#setName(String)}
*
* #param name
*/
public void setName(String name);
/**
* See {#link MetricNumber#setContext(String)}
*
* #return name of the metric.
*/
public String getName();
/**
* Get the list of violations attached to this metric.
*
* #return
*/
public List<ViolationProxy> getViolations();
}
#ProxyFor(value = MetricNumber.class, locator = IMetricEntityLocator.class)
public interface MetricNumberProxy extends MetricProxy {
public List<NumberRangeProxy> getRanges();
public void setRanges(List<NumberRangeProxy> ranges);
}
...
#ProxyFor(value = MetricDouble.class, locator = IMetricEntityLocator.class)
public interface MetricDoubleProxy extends MetricNumberProxy {
/* Properties when fetching the object for with clause */
public static String[] PROPERTIES = {"ranges"};
public Double getValue();
}
...
#ProxyFor(value = MetricPlot.class, locator = IMetricEntityLocator.class)
public interface MetricPlotProxy extends MetricProxy {
/**
* UI Name of the object.
*/
public String NAME = "Static Plot";
public String getPlotUrl();
}
This is a made up method from because I usually always return composite classes that may contain a list of metrics. That being said this will return me the base type of metrics, and then I can cast them.
#ExtraTypes({ MetricProxy.class, MetricNumberProxy.class, MetricDoubleProxy.class, MetricIntegerProxy.class})
#Service(value = AnalyticsOperationDao.class, locator = DaoServiceLocator.class)
public interface AnalyticsOperationRequest extends DaoRequest<AnalyticsOperationProxy> {
Request<List<<MetricProxy>> getSomeMetrics();
}
Not an exact method I use but will work for getting a proxy of type.
context.getSomeMetrics().with(MetricNumber.PROPERTIES).fire(new Receiver<List<MetricProxy>>() {
public void onSuccess(List<MetricProxy> metrics) {
for (MetricProxy metric : metrics) {
if (metric instanceof MetricDoubleProxy) {
logger.info("Got a class of double " + metric.getValue());
}
}
}
}
You will know if you are missing an #ExtraTypes annotation when you get the error stated above.
Hope that helps

GWTP Handlers are Thread safe?

I am using gwt-platform for my application development.
I opened 2 browsers running the same application, i did 2 same operations with different data, but the now the browsers on the same view accessing the similar handler action
now the issue is the 2 browsers has updated with first received data from handler..
i am not understanding why it is not recognized the browsers which send the request... so this means its not Threadsafe...?
I seen #RequestedScope annotation in the Guice is it useful when i use on execute() of Handler
any suggestions?
Thanks in advance...
Maybe...
You have to made your Actions thread-safe. (attrs has final, e.g., inject in constructor), and perharps your logic has to be thread-safe too.
Btw, can you post a example of your action?
With 2 browsers you should have 2 different instances of your app running. In your onModuleLoad(), just put a System.out.println(this);. You should see different result which means you have different instances.
If you run an action from Browser 1, the action will be executed only in Browser 1. I don't know what your action is doing but if it updates data in the datastore (or DB) and since both instances share the persistence layer, you will see the new data in Browser 2 too.
It's very unlikely that the action triggered in Browser 1 is executed on both Browsers. It would mean that they share the same event bus.
public class InfoAction extends UnsecuredActionImpl<Response<ObjectTO>>
{
private List<OpenTO> request;
private String machineId;
private int actionType;
private UserBean userBean;
/**
* This is been in the case of double dated flight.
*/
private String orignalFpesLegId;
public List<OpenTO> getRequest() {
return request;
}
public void setRequest(List<OpenTO> request) {
this.request = request;
}
public String getMachineId() {
return machineId;
}
public void setMachineId(String machineId) {
this.machineId = machineId;
}
/**
* #return the actionType
*/
public int getActionType() {
return actionType;
}
/**
* #param actionType the actionType to set
*/
public void setActionType(int actionType) {
this.actionType = actionType;
}
/**
* #param userBean the userBean to set
*/
public void setUserBean(UserBean userBean) {
this.userBean = userBean;
}
/**
* #return the userBean
*/
public UserBean getUserBean() {
return userBean;
}
}
Please find my action class code

Vala: D-BUS object implementing interface, error with properties

Is it possible to have a class annotated with [DBus (name = ...)] implement an interface?
Following the example at https://live.gnome.org/Vala/DBusServerSample, I am implementing a D-BUS client/server application.
One thing that I found peculiar about the example was that there was no separate interface definition. I would like to have the interface used by the client side in a separate file, and have the server class implement that interface. That way I can have the compiler tell me when I miss something.
This does not appear to work with properties though. The following definition is compatible with what I have:
/* interface.vala */
namespace org.test {
[DBus (name = "org.test.Items")]
public interface IItems : Object {
/**
* The object paths to the item instances.
*
* These objects are of type org.test.items.Item.
*/
public abstract ObjectPath[] items {
owned get;
}
/**
* The signal that is emitted when a new item is added.
*
* When this signal is emitted, the item will be available.
*
* #param id
* The object path to the item instance.
*/
public signal void item_added(ObjectPath id);
/**
* The signal that is emitted when an item is removed.
*
* When this signal is emitted, the item will be unavailable.
*
* #param id
* The object path to the item instance.
*/
public signal void item_removed(ObjectPath id);
/**
* Adds a new item.
*
* The URL will be parsed, and if it contains a valid item, it will be
* added.
*
* #param url
* The URL to the item. This should typically be the URL of the
* RSS feed.
* #return the ID of the item added, which can be used to query D-BUS
* for it
* #throws IOError if a D-BUS error occurs
*/
public abstract ObjectPath add_item(string url) throws IOError;
/**
* Removes an item.
*
* #param id
* The ID of the item to remove.
* #throws IOError if a D-BUS error occurs
*/
public abstract void remove_item(ObjectPath id) throws IOError;
}
}
/* server.vala */
using Gee;
namespace org.test {
[DBus (name = "org.test.Items")]
public class Items : DBUSObject, IItems {
private ArrayList<Item> _items;
[DBus (visible = false)]
protected override void dbus_register(DBusConnection conn,
ObjectPath path) throws IOError {
conn.register_object(path, this);
}
[DBus (visible = false)]
public Items() {
base("org.test.Items", "/org/test", "Items", true);
_items = new ArrayList<Item>();
}
[DBus (visible = false)]
~Items() {
unregister();
}
/**
* #see interface.vala::org.test.IItems.comics
*/
public ObjectPath[] items {
owned get {
ObjectPath[] result = {};
foreach (var item in _items) {
result += new ObjectPath(item.path);
}
return result;
}
}
/**
* #see interface.vala::org.test.IItems.add_comic
*/
public ObjectPath add_item(string url) throws IOError {
/* . . . */
}
/**
* #see interface.vala::org.test.IItems.remove_item
*/
public void remove_item(ObjectPath id) throws IOError {
/* . . . */
}
}
}
When I compile it, I get no error from valac, but when the generated C code is compiled, the linker complains: undefined reference to 'org_test_items_get_items'.
This function is referenced by _dbus_org_test_items_get_items, but it does not exist
It's obviously a bug. The right place to report bugs is http://bugzilla.gnome.org .