rest apis for exporting config.office.com - microsoft-graph-api

I'm trying to export Office Policies available in 2 place:
In Intune Endpoint manager (https://endpoint.microsoft.com)
In https://config.office.com
I'm generating a token (following intune rest api documentation) an I call:
GET https://config.office.com/api/OfficeSettings/policies HTTP/1.1
The error returned is:
WWW-Authenticate: Bearer error="invalid_token", error_description="S2S17001: SAL was able to validate the protocol, but validation failed as none of the inbound policies were satisfied. Validation failures: '33d566a7-b1b3-4676-b399-b215146b78c4: InvalidAudience."
Apparently the token is invalid and I didn't find any documentation for how to generate the right token.
Microsoft documentation is stating that the intune portal is entirely written on top of graph api but few calls (including this one) are making external calls (but pass the same bearer token).
Programmatically, the token is invalid.
The real question : is how to we read/write the Office Policies? (How do we generate an application token?).

Related

How to simply get a bearer token to send requests to Azure DevOps API?

I need to create an organizational feed to host nuget packages shared among projects on our Azure DevOps environment.
After several unsuccesful attempts and research, I discovered that the only way to create an organizational feed is, by design from Microsoft mouth, the Azure DevOps API.
Source for the claim : This question on VS dev community
and The MS docs on project-scoped feeds
Basically, I just need to be able to perform a POST here :
https://feeds.dev.azure.com/{organization}/_apis/packaging/feeds?api-version=5.1-preview.1
with the body :
{
"name": "{myfeedname}",
"hideDeletedPackageVersions": true,
"upstreamEnabled": true
}
And of course, a Bearer token to authenticate myself. That's the point where I'm confused.
What is the simplest way to obtain one ? I'm logged in through my company Microsoft AD account on my computer browser on Azure DevOps. I don't see any Bearer token that I can "steal" to use in PostMan in my browser dev tools.
The API docs described some relevant info, but I'm confused on how to use it in Postman :
Security oauth2
Type: oauth2
Flow: accessCode
Authorization URL: https://app.vssps.visualstudio.com/oauth2/authorize&response_type=Assertion
Token URL: https://app.vssps.visualstudio.com/oauth2/token?client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
Scopes Name Description
vso.packaging_write Grants the ability to
create and read feeds and packages.
Here is the interface in Postman for OAuth2:
Ican see how the info in the docs relates to the fields 1 - 2 - 3 - 4, but then, what callback url should I use ? What credentials ? my Microsoft email + password from AD ?
I tried this, and all I seem to get is this from Postman :
{"$id":"1","innerException":null,"message":"A potentially dangerous Request.Path value was detected from the client (&).","typeName":"System.Web.HttpException, System.Web","typeKey":"HttpException","errorCode":0,"eventId":0}
TLDR
How do I properly proceed to get a token with Postman, or other tool to manually execute my one-time request to Azure DevOps REST API ?
notes :
Following info here : Unable to get Authorization code for Devops using Postman oAuth2.0
, leading here : https://github.com/Microsoft/azure-devops-auth-samples/tree/master/OAuthWebSample , I understand that I have to register and run a whole web application. Am I understanding this correctly ? I there a simpler way ?
I understand that I have to register and run a whole web application. Am I understanding this correctly ? I there a simpler way ?
Yes, you are right. You have to register whole web application.
As the interface in Postman for OAuth2, we need provide the CallbackUrl, ClientID, ClientSecret and so on. Then, we check the document Requesting an OAuth 2.0 token, we could to know the Callback URL is:
The client application callback URL redirected to after auth, and that
should be registered with the API provider.
So, we have to register an OAuth client app in Azure DevOps (https://app.vsaex.visualstudio.com/app/register), then we could get the following information, like:
You could check the document Authorize access to VSTS REST APIs with OAuth 2.0 for some more details.
AFAIK, there is currently no simpler way to get a bearer token to send requests to the Azure DevOps API.
Hope this helps.

Onedrive API rejects access token (CompactToken parsing failed with error code: 8004920A)

Hopefully I'm missing something very simple. According to this documentation to get an access token I need to hit the following url:
https://login.live.com/oauth20_authorize.srf?client_id={client_id}&scope={scope}
&response_type=token&redirect_uri={redirect_uri}
So far this appears to be working as the returned url I get contains
/#access_token=EwAYA61DBAAUcSSzo.......
According to the token flow documentation above,
You can use the value of access_token to make requests to the OneDrive API.
According to this page,
Your app provides the access token in each request, through an HTTP header:
Authorization: bearer {token}
When running curl I give it the exact token I was given before,
curl -X GET \
https://graph.microsoft.com/v1.0/drive \
-H 'Authorization: Bearer EwAYA61DBAAUcSSzoTJJs.....
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "CompactToken parsing failed with error code: 8004920A",
"innerError": {
"request-id": "8780c600-2b7f-45a0-b484-7eca9dfd2697",
"date": "2019-01-25T19:33:22"
}
}
}
Why is the token they provided not working?
What I've tried so far:
changing the case of bearer in the header
wrapping said token in {}
generating new tokens
URL decoding said token
One thing to note: the tokens I am receiving are not JWT tokens. Googling the error code pulls up several Stack Overflow questions that seem to imply the graph api is expecting a JWT. If this is the case, am I missing a step to obtaining it?
You can't call Microsoft Graph API after completing the authentication flow for Microsoft accounts (OneDrive personal).
In addition, the authorization process with Microsoft accounts is no longer recommended according the docs and new applications should be developed using Microsoft Graph:
This topic contains information about authorizing an application using Microsoft accounts for OneDrive personal. However, this approach is no longer recommended. New applications should be developed using Microsoft Graph and follow the authorization process in Authorization and sign-in for OneDrive in Microsoft Graph.

Configuration of Microsoft Graph OAuth2 authentication in Spring Security - Error AADSTS90014

I am writing an SSO provider for MS Graph APIs Azure AD v2 endpoint leveraging Spring OAuth2.
I am progressing with the implementation and constant testing but I stumbled upon an error returned by AAD which is puzzling me. After all, this should all be plain standard OAuth 2 flow.
I successfully configured my application on MS dev portal, providing a localhost redirect URL (which, for the record, is the only supporting the http scheme. Kudos to MS). So when I invoke http://localhost/myapp/auth/office365 Spring security successfully intercepts the invocation, provides a correct redirect to my browser with client ID to https://login.microsoftonline.com/common/oauth2/v2.0/authorize with expected parameters.
Microsoft shows a consent screen to me, after which I get redirected back to my Spring Security application via HTTP GET with expected authorization code parameter.
The problem is that when the application tries to negotiate the given authorization code for a bearer token headaches start. Spring Security invokes a POST to https://login.microsoftonline.com/common/oauth2/v2.0/token but ends in 401 error.
Here is the stack trace
error="invalid_request", error_description="AADSTS90014: The request body must contain the following parameter: 'client_id'.
Trace ID: 9acd2a10-1cfb-443f-9c57-78d608c00c00
Correlation ID: bf063914-8926-4e8f-b102-7522d0e3b0af
Timestamp: 2017-10-09 15:51:44Z", correlation_id="bf063914-8926-4e8f-b102-7522d0e3b0af", error_codes="[90014]", timestamp="2017-10-09 15:51:44Z", trace_id="9acd2a10-1cfb-443f-9c57-78d608c00c00"
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:100)
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:235)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:215)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:235)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:621)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:209)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
I have looked into Spring security implementation to find the cause,.
It happens that the error message error="invalid_request", error_description="AADSTS90014: The request body must contain the following parameter: 'client_id'. is self explanatory: MS Graph wants the client ID (which is still supplied by the basic authentication header) in the request body. Stop for a moment. I want to use plain old Spring Security and not third-party specific jars in order not to pollute my classpath.
Looking into Java source code of Spring OAuth 2 the problem is damn clear. Spring uses the client ID only in getParametersForAuthorizeRequest, which is used to generate the redirect URL. When it comes to getParametersForTokenRequest the client ID is not specified in the form.
Question: who is right here? How do I tell Spring that MS wants the client id in the token request after an authorization code has been obtained?
Just to clarify, you're not actually authenticating with or against Microsoft Graph. You're actually authenticating against Azure Active Directory. The Microsoft Graph API accepts the bearer token you'll end up with but it doesn't issue the access token itself.
It isn't clear which endpoint you're using for the Authorization Code flow, AAD has two of them: v1 and v2. The primary difference being that v2 uses a central registration and can authenticate both work/school and personal accounts.
Regardless of the endpoint, you do need to supply the clientid in the request body when you're requesting an access token. There are actually several values you need to provide in the body. Also note that these need to be provided as application/x-www-form-urlencoded.
For the v1 endpoint you provide (line breaks for readability only):
grant_type=authorization_code
&client_id={client-id}
&code={authoization-code}
&redirect_uri={redirect-uri}
&client_secret={client-secret}
&resource={resource-uri}
The v2 endpoint is almost identical but uses scope instead of resource:
grant_type=authorization_code
&client_id={client-id}
&code={authoization-code}
&redirect_uri={redirect-uri}
&client_secret={client-secret}
&scope={scopes}
OP's edit
Now, back to Spring Security. Spring by default uses an HTTP basic authentication scheme against Azure AD. In that scheme, the client ID and secret are encoded into the HTTP Authorization header, then the form only contains the authorization code and state parameter, so here is why I (the OP, ndr) was puzzled about why AAD refused the authorization.
In order to pass client ID and secret into the form, we can tell Spring Security to use a different supported authentication scheme. The form authentication scheme will push the client ID and secret into the form.
The below code works and retrieves the access token.
<oauth2:resource
id="msAdAuthenticationSource"
client-id="${oauth.appId}"
client-secret="${oauth.appSecret}"
type="authorization_code"
authentication-scheme="form"
client-authentication-scheme="form"
use-current-uri="true"
user-authorization-uri="${oauth.authorizationUri}"
access-token-uri="${oauth.accessTokenUri}"
scope="${oauth.scopes}"
pre-established-redirect-uri="${oauth.redirectUri}" />
Please note the two
authentication-scheme="form"
client-authentication-scheme="form"
Problem solved, a lot more to come!

FusionTables Insert works in OAuth2 Playground, but not as HTTPS Post in other systems

Hello kind people of the internet,
We can successfully use the Google Oauth 2.0 Playground to make a simple sql POST insert to a FusionTable, but when attempt the same basic HTTPS POST operation in anything else (from back end system, another browser session, Postman chrome tool, hurl.it, etc, etc), we always get a 403 error:
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
I'm puzzled why the error is returned when doing an HTTPS post from other systems (other than OAuth playground)?...as at the time I'm supplying an active Access token (cut-n-pasted Access token from OAuth playground).
The successful-working-good Request block in OAuth 2.0 Playground is below (but the Access token is of course now expired):
POST /fusiontables/v1/query?sql=INSERT INTO 1CqwRGEEn4L0gN66JwGvCR5yOI8miNMVijcp4XlE (Name, Age) VALUES ('Forrest', 57) HTTP/1.1
Host: www.googleapis.com
Content-type: application/json
Authorization: Bearer ya29.AHES6ZRr9CkHptvLaYlba_u6wceIh29urI8FjFp8xMP08AcBm2qpHg
Here's the direct URL that is generated by several different REST based tools I'm attempting to use to simulate the HTTPS request to do a POST sql insert to FusionTables (which again: always generates a 403 error even with an active Access token):
https://www.googleapis.com/fusiontables/v1/query?sql=INSERT%20INTO%201CqwRGEEn4L0gN66JwGvCR5yOI8miNMVijcp4XlE%20(Name,%20Age)%20VALUES%20('Jim',%2057)=&Content-length:=0&Content-type:%20=application/json&Authorization:=%20Bearer%20ya29.AHES6ZRr9CkHptvLaYlba_u6wceIh29urI8FjFp8xMP08AcBm2qpHg
Some other notes:
-In my Google APIs Console, I'm using the "Client ID for web applications".
-I updated the FusionTable properties with the Api console email-address to allow edit capability on the fusiont table used in the above sql (1CqwRGEEn4L0gN66JwGvCR5yOI8miNMVijcp4XlE) Adding the email for edit capability to the FusionTable properties was kindly suggested by Odi for Service accounts on another related post on FusionTables).
Any help in explaining why HTTPS Post works in the OAuth playground for a sql insert to FusionTables, but not anywhere else would surely be appreciated...there must be something I'm missing, as supposedly the OAuth playground was to help illuminate how OAuth works at a detailed level so we could handle in other systems that don't necessarily have a developed OAuth library.
Update 8/23, per the suggested answer...here's a URL syntax that works in POSTMAN and uses both the OAuth API key and an active Access token which was obtained using the OAuth playground (access token is of course fake/expired).
https://www.googleapis.com/fusiontables/v1/query?sql=INSERT%20INTO%201CqwRGEEn4L0gN66JwGvCR5yOI8miNMVijcp4XlE%20(Name,%20Age)%20VALUES%20('Bob',%2031)=&Content-length:=0&Content-type:%20=application/json&key={OAuth API key}&access_token=ya29.AHES6ZST_c2CjdXeIyG8LwkprQMGGfoW45sonX0d1H51234
Try adding your API key to the POST. Even though the message refers to authentication I'm pretty sure it's not OAuth authentication but your API usage that needs to be verified.

Calling customer service results in 401 Unauthorized

We are trying to connect to a custom Dynamics 365 Finance service operation but are struggling to authorize.
We've set up an app registration
Redirect_uri set to the dynamics url (root)
Enabled implicit grant (both for access tokens and ID tokens)
Single tenant
Assigned the "Dynamics ERP > CustomService.FullAccess" API permission
Assigned the "Dynamics ERP > Odata.FullAccess" API permission
Assigned "Dynamicd ERP > Connector.FullAccess" API permission + granted admin consent for entire AD
Created a secret
We've added the Application (client ID) within the Dynamics 365 environment with a user which has System Administrator role
We can successfully retrieve access tokens both via Postman and .NET (Microsoft.IdentityModel.Clients.ActiveDirectory)
we tried to reach both https://xxxxxxdevaossoap.cloudax.dynamics.com &https://xxxxxxdevaos.cloudax.dynamics.com
Yet when we call custom services, we get a 401 UnAuthorized
A call to Odata also fails for the same reason.
Verify resource in your request for OAuth token (and verify token at https://jwt.io for aud (Audience) field).
It should be same as your primary url without / at the end (like https://d365fo-10-12345678baef10230aos.cloudax.dynamics.com).
Also verify that Azure Active Directory applications (mi=SysAADClientTable) Client Id is equal to appid field in the token (and without any special characters).
You can always inspect Windows Event Log Microsoft-Dynamics-AX-WebApi/Operational
There is good information like this:
Source: Microsoft-Dynamics-AX-WebApi
Category: WebApiOwinConfigurationMissingError
Level: Error
Description: Web API Owin Authentication Configuration Missing Error
infoMessage: Can read the token but failed validating token with exception
'IDX10214: Audience validation failed.
Audiences: 'https://d365fo-10-12345678baef10230aos.cloudax.dynamics.com/'.
Did not match: validationParameters.
ValidAudience: 'null' or validationParameters.ValidAudiences:
'https://d365fo-10-12345678baef10230aos.cloudax.dynamics.com,
00000015-0000-0000-c000-000000000000,
Microsoft.ERP''

Resources