Blog & News

Articles, insights and thinking from software development vendor

Java-service integration with SharePoint Online via REST API

It is often a challenge to optimize the work that is performed with the various repositories (sets of  the same types of data) during the development of enterprise information management systems (IMS), as the interaction with them causes the filling and editing of numerous forms. Design, planning, and development of such forms may take a few weeks, and it delays the start of systems operation.

Solutions like SharePoint Online help to launch subsystem of registers maintenance rapidly. They provide not only functionality for forms building and storing the data in different formats but also the possibility of access differentiation and integration, and much more. Developers need only to implement a mechanism of data manipulation in SharePoint. At WaveAccess, we used REST API solution for such implementation.

Authentication

As SharePoint Online has strict safety standards, authentication for working with REST API consists of three steps:

1. Get the security token from Microsoft authentication portal:

public String receiveSecurityToken() throws TransformerException, URISyntaxException {
  RequestEntity<String> requestEntity = new RequestEntity<>(buildSecurityTokenRequestEnvelope(), HttpMethod.POST, new URI("https://login.microsoftonline.com/extSTS.srf"));
  ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
  DOMResult result = new DOMResult();
  Transformer transformer = TransformerFactory.newInstance().newTransformer();
  transformer.transform(new StringSource(responseEntity.getBody()), result);
  Document definitionDocument = (Document) result.getNode();
  String securityToken = xPathExpression.evaluateAsString(definitionDocument);
  if (StringUtils.isBlank(securityToken)) { 
    throw new SharePointAuthenticationException("Unable to authenticate: empty token");
  }
  return securityToken;
}

The envelope that is sent to the portal has the following format:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action> 
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo> 
    <a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</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">
      <o:UsernameToken>
        <o:Username>[username]</o:Username>
        <o:Password>[password]</o:Password>
      </o:UsernameToken>
    </o:Security>
  </s:Header>
  <s:Body>
    <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
      <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
        <a:EndpointReference>
          <a:Address>[SharePoint domain address]</a:Address>
        </a:EndpointReference>
      </wsp:AppliesTo> 
      <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
      <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
      <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
    </t:RequestSecurityToken>
  </s:Body>
</s:Envelope>

2. Get the cookies from the SharePoint Online server:

public List<String> getSignInCookies(String securityToken) throws TransformerException, URISyntaxException {
  RequestEntity<String> requestEntity = new RequestEntity<>(securityToken, HttpMethod.POST, new URI("[SharePoint domain address]/_forms/default.aspx?wa=wsignin1.0"));
  ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
  HttpHeaders headers = responseEntity.getHeaders();
  List<String> cookies = headers.get("Set-Cookie");
  if (CollectionUtils.isEmpty(cookies)) {
    throw new SharePointSignInException("Unable to sign in: no cookies returned in response");
  } 
  return cookies;
}

3. Get the signature for requests to the SharePoint Online server:

public String getFormDigestValue(List<String> cookies) throws IOException, URISyntaxException, TransformerException, JSONException {
  MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
  headers.add("Cookie", Joiner.on(';').join(cookies));
  headers.add("Accept", "application/json;odata=verbose");
  headers.add("X-ClientService-ClientTag", "SDK-JAVA");
  RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.POST, new URI("[SharePoint domain address]/_api/contextinfo"));
  ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
  JSONObject json = new JSONObject(responseEntity.getBody());
  return json.getJSONObject("d").getJSONObject("GetContextWebInformation").getString("FormDigestValue"); 
}

Running queries to the SharePoint Online server

Now we have everything that is needed to run queries to the SharePoint Online server. In the request headers, you must add the received cookies, put the required Content-Type and add a signature. Generally, the method looks like this:

public String performHttpRequest(String path, String json, boolean isUpdate) throws Exception {
  String securityToken = service.receiveSecurityToken();
  List<String> cookies = service.getSignInCookies(securityToken);
  String formDigestValue = service.getFormDigestValue(cookies);
  MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
  headers.add("Cookie", Joiner.on(';').join(cookies));
  headers.add("Content-type", "application/json;odata=verbose");
  headers.add("X-RequestDigest", formDigestValue);
  if (isUpdate) {
    headers.add("X-HTTP-Method", "MERGE");
    headers.add("IF-MATCH", "*");
  }
  RequestEntity<String> requestEntity = new RequestEntity<>(json, headers, HttpMethod.POST, new URI(path));
  ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
  return responseEntity.getBody();
}

It should be noted that the security token has an expiration time - one day. So this makes it possible to optimize the performance of the service using cache.

Conclusion

Even despite the restrictions and difficulties of integration, SharePoint Online provides many useful features and completed environment. This helps to reduce the time costs of launching such projects which require the processing of large amount of forms.

If in the current project you need to integrate Java-service with SharePoint Online via REST API, or to develop a corporate management information system, e-mail us at

hello@wave-access.com

Order a phone call

Convenient time to call:

Cancel

Get in touch

Attach
Your file up to 30 mb
Cancel