4

I'm trying to connect Sharepoint online REST API using Java. Retrieved cookies -rtfa and fedAuth. Also got xForm Digest value and trying to authenticate. But it always throws Authentication error.

private void getSharePointContents(String rtFa, String fedAuth, String XRequestDigest,String sharePointServerUrl) {
    DefaultHttpClient httpClient = new DefaultHttpClient();

    try {
        HttpGet getRequest = new HttpGet(sharePointServerUrl);
        System.out.println("rtfa :"+ rtFa + "\n , FedAuth: " +fedAuth + "\n XRequestDigest: "+XRequestDigest);
        getRequest.addHeader("Cookie", "rtFa="+rtFa+";FedAuth="+fedAuth);
        getRequest.addHeader("Authorization", "Bearer"+XRequestDigest);
        getRequest.addHeader("accept", "application/json");

        HttpResponse response = httpClient.execute(getRequest);

        if (response.getStatusLine().getStatusCode() == 200) {               
            BufferedReader br = new BufferedReader(
                    new InputStreamReader((response.getEntity().getContent())));
            String output;
            while ((output = br.readLine()) != null) {
                System.out.println(output);
            }
        }else{
            System.out.println(response.getStatusLine().getStatusCode());
            throw new RuntimeException("Failed : HTTP error code : "
                    + response.getStatusLine().getStatusCode());
        }

    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        httpClient.getConnectionManager().shutdown();
    }

This is the error i'm getting:

Apr 03, 2018 3:59:46 PM org.apache.http.impl.client.DefaultRequestDirector handleResponse WARNING: Authentication error: Unable to respond to any of these challenges: {bearer=WWW-Authenticate: Bearer realm="",client_id="",trusted_issuers="",authorization_uri="https://login.windows.net/common/oauth2/authorize"} 401 Exception in thread "main" java.lang.RuntimeException: Failed : HTTP error code : 401 at com.sharepointOnline.SharepointOnlineAuthenticator.getFolderByServerRelativeUrl(SharepointOnlineAuthenticator.java:99) at com.sharepointOnline.SharepointOnlineAuthenticator.main(SharepointOnlineAuthenticator.java:73)

Can someone please help with this error?

3
  • Did you try to use Office Graph instead of SharePoint API?
    – jaloplo
    Commented Jul 31, 2019 at 14:37
  • can anybody send me the source code
    – Kiran
    Commented Oct 14, 2019 at 4:28
  • Don't you want to create a simple java API ? lots of people are suffering from the complexity !!! thanks
    – user94782
    Commented Feb 3, 2021 at 19:34

2 Answers 2

6

Here is a demo for your reference, We access SharePoint online and use REST API to upload a file in JAVA.

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(FormDigestValue) 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"); 

}

Finally, we can call REST API to upload the document as below.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files/add(url='a.txt',overwrite=true)

method: POST body: "Contents of file" Headers: Authorization: "Bearer " + accessToken X-RequestDigest: form digest value content-length:length of post body

public String performHttpRequest(String path, String json, boolean isUpdate) throws Exception {

String securityToken = receiveSecurityToken();
List<String> cookies = getSignInCookies(securityToken);
String formDigestValue = 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);                     

RequestEntity<String> requestEntity = new RequestEntity<>(json, 
    headers, HttpMethod.POST, new URI(path));

ResponseEntity<String> responseEntity = 
    restTemplate.exchange(requestEntity, String.class);

return responseEntity.getBody();
}

More information for your reference: SharePoint Online remote authentication (and Doc upload)

You can refer to my answer: How to upload files to sharepoint site's document library using Graph API on android

7
  • where we have to pass this xml envelope ? Commented Oct 14, 2018 at 13:17
  • @Anurag_BEHS request to login.microsoftonline.com/extSTS.srf with post method
    – Lee Liu
    Commented Oct 17, 2018 at 2:16
  • do u mean we have to pass this xml envelope as post body of step 1 ? in step 1 method what is- buildSecurityTokenRequestEnvelope() method what we have to do here ? Commented Oct 19, 2018 at 17:55
  • @Anurag_BEHS Yes, we have to pass the xml envelope as post body of step 1, the code is not very detailed, it only porvide the idea. I recommend you to refer to: paulryan.com.au/2014/spo-remote-authentication-rest
    – Lee Liu
    Commented Oct 22, 2018 at 2:02
  • @LeeLiu In your answer you have used <o:Username>[username]</o:Username>, here username mainly is email address. So can we use anything else other then email address. Commented Feb 11, 2019 at 12:00
2

Maybe my answer is a bit late, but, can't you use the Microsoft Graph ?

this is a quickstart from Microsoft for java development : https://github.com/OfficeDev/Office-365-SDK-for-Java

And the docs to connect to SPO : https://docs.microsoft.com/en-us/graph/api/resources/sharepoint?view=graph-rest-1.0

Not the answer you're looking for? Browse other questions tagged or ask your own question.