I have a requirement to create restful service using WebApi in MS Dynamics and create a client in Java and hit the MS Dynamics Web Service. If I want to create a restful service in MS Dynamics through WebApi, is it mandatory that I need to have OAUTH implemented? Can create a service and hit from Java without authentication?
My another question is, is it possible to use our custom authentication method like call a another web service from MS Dynamics and validate and if authorised user then send data.
I am ok in implementing Java client but I am not familiar with MS Dynamics and not able to find any help from net.
Here's an example from Jason Lattimer's blog post: CRM Web API Using Java
Again our friends at Microsoft help us out on the authentication front
by providing a version of the Azure Active Directory Authentication
Library (ADAL) for Java. You can set up a Maven dependency with the
info here:
http://mvnrepository.com/artifact/com.microsoft.azure/adal4j
In this case I’m authentication using a hardcoded username and
password.
//Azure Application Client ID
private final static String CLIENT_ID = "00000000-0000-0000-0000-000000000000";
//CRM URL
private final static String RESOURCE = "https://org.crm.dynamics.com";
//O365 credentials for authentication w/o login prompt
private final static String USERNAME = "administrator#org.onmicrosoft.com";
private final static String PASSWORD = "password";
//Azure Directory OAUTH 2.0 AUTHORIZATION ENDPOINT
private final static String AUTHORITY =
"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000";
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(AUTHORITY, false, service);
Future<AuthenticationResult> future = context.acquireToken(RESOURCE,
CLIENT_ID,
USERNAME,
PASSWORD, null);
result = future.get();
} finally {
service.shutdown();
}
String token = result.getAccessToken();
The other thing I stumbled upon is that Java’s HttpURLConnection for
making HTTP requests doesn’t support the PATCH method natively (which
is used by the Web API when doing updates to multiple fields). This
was solved specifying a POST method and adding an additional
“X-HTTP-Method-Override” property.
connection.setRequestProperty("X-HTTP-Method-Override", "PATCH");
connection.setRequestMethod("POST");
You can check out the code on GitHub:
https://github.com/jlattimer/CrmWebApiJava
Related
I'm new to Azure and I'm struggling to get a simple demo working.
I'm trying to write a daemon client that accesses a blob. The access must be via a registered app, and I want to explicitly acquire an access token.
As a warm-up I wrote a demo that accesses the blob using the blob api, and this works OK:
ClientCertificateCredential credentials = new ClientCertificateCredentialBuilder()
.clientId("11518eab-7b5a-493c-8d12-27731fe51341")
.tenantId("4b106bc5-7518-4f86-a259-f5726d124732")
.pemCertificate("/home/william/cert/new/azure.pem")
.build();
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.credential(credentials)
.endpoint("https://wemsa.blob.core.windows.net/")
.buildClient();
BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("wemco");
blobContainerClient.getBlobClient("spiral.jpeg")
.downloadToFile("/home/william/blob.jpeg");
The above code uses my registered app to create a BlobClient that downloads my blob file. The fact that this works shows me that my app does have the role required to access my storage container.
I want to create a second demo that does the same thing, but I want to get an access token explicitly and use it to authorise a plain http request to the blob api. So far this is what I've produced:
private static final String TENANT_ID = "4b106bc5-7518-4f86-a259-f5726d124732";
private static final String CLIENT_ID = "11518eab-7b5a-493c-8d12-27731fe51341";
private static final String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_ID;
private static final Set<String> SCOPE = Collections.singleton("api://" + CLIENT_ID + "/.default");
InputStream pkcs12Cert = new FileInputStream("/home/william/cert/new/azure.p12");
String certPwd = "password123";
IClientCredential credential = ClientCredentialFactory.createFromCertificate(pkcs12Cert, certPwd);
ConfidentialClientApplication cca = ConfidentialClientApplication
.builder(CLIENT_ID, credential).authority(AUTHORITY).build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(SCOPE).build();
IAuthenticationResult result = cca.acquireToken(parameters).join();
String token = result.accessToken();
URI uri = new URI("https://wemsa.blob.core.windows.net/wemco/spiral.jpeg");
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.header("Authorization", "Bearer " + token)
.header("Date", formatNow())
.header("x-ms-version", "2020-06-12")
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode()); // 401 !!!
This uses the same registered app as the first demo. Debugging tells me that it is successfully getting access tokens. But, when I try to use them I always get a 401 response. I had hoped that since the first demo works OK, the second demo would automatically work as well - but it doesn't.
Is what I'm trying to do even possible?
Is there something wrong with the code in my second demo?
Do I need to do more setup in Azure before demo 2 will work? Some of the Azure docs mention creating an app role, which I tried, but I didn't know what to do with it.
Any suggestions ?
Additional info: This is what I did in Azure (accepting defaults for everything):
create storage account wemsa
create container wemco inside wemsa
upload (a small) file 'spiral.jpeg' into container wemco
create app registration wemapp
upload certificate 'azure.crt' into wemapp
Then I returned to the container wemco and:
granted role 'Storage Blob Data Contributor' to wemapp
This was enough to get demo 1 working.
Fixed by changing the scope (i.e. the requested resource) to azure storage:
private static final Set<String> SCOPE =
Collections.singleton("https://storage.azure.com//.default");
After making this change I was able to download my blob file using the demo 2 code in the original posting.
I am using the Swagger Generator website to generate the code for an API in Java. The API specifications are public and available here. As you can see, seems like the JSON doesn't have any Authentication configuration in it, but the API actually uses an OAuth authentication using "Microsoft Identity Platform" as authority and using an Application ID and Secret to get a JWT. I can obtain the token in Java using external libraries, but I'd like to integrate the process in Swagger as much as possible.
By importing into the generator the previous JSON, obviously no Authorization is configured and all API calls fail. I modified the JSON and added these parameters:
"securityDefinition":{
"civnext_oauth":{
"type":"oauth2",
"authorizationUrl":"https://login.microsoftonline.com/............./oauth2/token",
"flow":"application",
"scopes":{
"write:protocollo":"Modify Protocolli",
"read:protocollo":"Read Protocolli"
}
}
},
And then, for every Path I added
"security":{
"civnext_oauth":[
"write:protocollo",
"read:protocollo"
]
},
I generated all the files and imported them correctly in my project, but I still could not manage to test an authenticated API call.
In particular:
I don't know if my changes in the JSON are correct and if it is the right procedure. Am I missing something? Am I doing something wrong?
I do not know the right way to handle the authentication and API calls in Java after generating the code. Right now I am doing like this:
String authority = "https://login.microsoftonline.com/............./oauth2/token";
ExecutorService service = Executors.newFixedThreadPool(1);
AuthenticationContext context = new AuthenticationContext(authority, true, service);
Future<AuthenticationResult> future = context.acquireToken(
"api_resource_path",
new ClientCredential(
"app_id",
"secret"),
null);
AuthenticationResult result = future.get();
OAuth authentication = new OAuth();
authentication.setAccessToken(result.getAccessToken());
ApiClient apiClient = new ApiClient();
apiClient.getAuthentications().put("oauth2", authentication);
apiClient.setBasePath("basepath");
apiClient.setAccessToken(result.getAccessToken());
ProtocolloApi api = new ProtocolloApi();
api.setApiClient(apiClient);
Call call = api.protocolloGetTipoPostaCall("1.0", null, null);
Response response = call.execute();
System.out.println(response.toString());
But since I am missing experience and documentation, this is just improvisation.
Can you help me?
Best regards,
Giammarco
I need to read mails from an Outlook mailbox via Graph API. The application I am writing is a scheduled batch job without user interaction. I can't use application permissions, because of compliance reasons. The application must not be able to access all mailboxes on the tenant. I use delegated permissions for a technical user that got shared the allowed mailboxes to achieve that. I was able to get a JWT Access Token via ADAL4J and successfully called some APIs with it, but whenever I try to read a mailbox even the technical user mailbox I get a 403 forbidden.
I started with this official [sample] (https://github.com/Azure-Samples/active-directory-java-native-headless/). After setting up my Application in Azure this sample worked right away. I then changed the Graph call to "https://graph.microsoft.com/v1.0/me/messages" and suddenly I got a 403 Forbidden. To avoid permission problems I added all delegated permissions available in Azure AD to the application and provided Administrator consent for everything. That unfortunatly changed nothing. When I check the contents of my token I see the scp field containing all the permissions. Whats strange is that I can actually write the mailbox. I can write to the draft folder via Graph API. But when I take the returned message ID and try to query the same message I just created I again get a 403 Forbidden.
Getting the token
private static AuthenticationResult getAccessTokenFromUserCredentials(
String username, String password) throws Exception {
AuthenticationContext context;
AuthenticationResult result;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(AUTHORITY, false, service);
Future<AuthenticationResult> future = context.acquireToken(
"https://graph.microsoft.com", CLIENT_ID, username, password,
null);
result = future.get();
} finally {
service.shutdown();
}
return result;
}
Calling the messages endpoint:
URL url = new URL("https://graph.microsoft.com/v1.0/me/messages");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
conn.setRequestProperty("Accept","application/json");
int httpResponseCode = conn.getResponseCode();
Change the api version to beta will solve this issue.
https://graph.microsoft.com/beta/me/messages
Hello I face some problem, I'm not able to to call webservice from java and send the result to flex side.
the process
the user launches the application and lands on an authentication form
The user enters login and password and submits the authentication form
Submission call on java side a remoteservice checkUserCredetialFromLdap()
inside this java method I try to call an external ldap webservice as shown below.
The class responsible for ldap ws call is in custom jar (Maven dependencies)
public User checkUserCredetialFromLdap(String identifiant, String password) throws EmmBusinessException, LdapServiceException{
User myUser = null;
User myCompleteUser = null;
//initialization of webservice with the endpoint URL failed
Axis1LdapWsAuth ws = new Axis1LdapWsAuth(Config.getProperties().getProperty("endpoint.url"));
try{
//authentication using webservice
String csif_sessionID =ws.login(identifiant, password);
....
}
}catch(LdapServiceException lse)
{
EmmBusinessException emmB = new EmmBusinessException(lse,this,"","Unable to get User",Level.WARNING);
log(emmB);
throw (emmB);
}
catch (Exception t) {
EmmBusinessException emmB = new EmmBusinessException(t,this,"","Unable to get User",Level.WARNING);
log(emmB);
throw (emmB);
} finally {
finish();
}
return myCompleteUser;
}
I know it's possible to call webservice on flex side using RPC, but I don't want to do that, but for some reason I need to and have to call webservice from java side.
is't possible ? How can I do that ?
I suggest you to:
Develop a kind of proxy ldap webservice whose will do the bridge between flex app and your custom ldap authentication process
Use HttpService from flex to send parameter to the proxy ldap
Use proxy ldap to consume the checkUserCredetialFromLdap api with parameter get from flex
How can I authenticate programmatically to Google?
Now that ClientLogin (https://developers.google.com/accounts/docs/AuthForInstalledApps)
is deprecated, how can we perform a programmatic authentication to Google with OAuth2?
With ClientLogin we could perform a post to
https://www.google.com/accounts/ClientLogin
with email and password parameters and obtain the authentication token.
With OAuth2 i can't find a solution!
#
My app is a java background process.
I saw, following this link: developers.google.com/accounts/docs/OAuth2InstalledApp#refresh, how to obtain a new access token using a refreshed token.
The problem is that I can't find a java example about how to instantiate an Analytics object (for example) to perform a query when I have a new valid access token
This is my code that returns a 401 Invalid credentials when invoke the "execute()":
public class Test {
static final String client_id = "MY_CLIENT_ID";
static final String client_secret = "MY_SECRET";
static final String appName = "MY_APP";
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
static String access_token = "xxxx";
static String refreshToken = "yyyyy";
public static void main (String args[]){
try {
GoogleCredential credential =
new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(client_id, client_secret).build();
credential.setAccessToken(access_token);
credential.setRefreshToken(refreshToken);
//GoogleCredential
Analytics analytics = Analytics.builder(HTTP_TRANSPORT, JSON_FACTORY)
.setApplicationName(appName)
.setHttpRequestInitializer(credential)
.build();
Accounts accounts = analytics.management().accounts().list().execute();
} catch (Exception e) {
e.printStackTrace();
}
}
What is the problem?
Check the OAuth 2 flow for Installed Application:
https://developers.google.com/accounts/docs/OAuth2InstalledApp
It still requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.
For alternative solutions, check the Device flow or Service Accounts, they are explained in the same documentation set.
I found the Google Java client to be overly complex and poorly documented. Here's plain and simple Servlet example with Google Oauth2. For a background process you'll need to request access_type=offline. As others have mentioned you need the user to do a one time authorization. After that you can request refresh tokens as google tokens expire in an hour.
Although I appreciate that the OP was originally targeting the OAuth2InstalledApp approach, I would like to point out a working solution using the OAuth2WebServer approach. They don't differ significantly and this worked for me. I have found the google OAuth library to be pretty good as it will handle most of the OAuth dance for you and it makes it easy to refresh the access token. The solution below depends on using a pre-obtained refresh token.
As the accepted answer states, to get OAuth authentication working (even for a Java background process) where the request relies upon access to user data
requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.
From previous comments by the OP I see the following
So I followed OAuth2 for Web Server Applications (here offline access is documented) but I have still problems.
1) I perform the first request via browser and I obtain autenticaton code for offline access
2) I perform a java post of the authentication code and obtain acces token and refresh token
The approach I used is more like
1) I perform the first request via a browser and obtain the refresh token for offline access
2) In java I provide the refresh token to the library and the library will obtain the access token etc
specifically, using the google-api-java-client library the code is quite straightforward and note that I haven't set an access token as the OP did, as I am calling credential.refreshToken(); elsewhere. (I check if I have a valid access token already and if not call refresh prior to the API call)
private Credential generateCredentialWithUserApprovedToken() throws IOException,
GeneralSecurityException {
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
InputStreamReader inputStreamReader =
new InputStreamReader(jsonFileResourceForClient.getInputStream());
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, inputStreamReader);
return new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setClientSecrets(clientSecrets).build().setRefreshToken(REFRESH_TOKEN);
}
Note this covers step 2 of my approach, and the REFRESH_TOKEN mentioned in step 1 can be obtained as explained below.
First there is a prior set up of a web app creating an OAuth 2.0 client ID on the Google console for Credentials where you end up with a downloaded json file which will be read into the GoogleClientSecrets object.
i.e.
Make sure you add the Google playground callback uri into Authorized redirect URIs
Then you have your client id and the client secret ready for the playground and you can also download the json which you can pull into your Java code.
The REFRESH_TOKEN is obtained by sending a request to the google oauth playground with the following configuration. Note that prior to Step 1 and selecting your scope you should go to settings to check that you are providing you own credentials and add your client id and secret just below that
Note that the Access type is Offline, which corresponds to this.
There is also a nice explanation on grabbing the refresh token here https://www.youtube.com/watch?v=hfWe1gPCnzc
That is enough to get going and is a one time set up!
Regarding refresh tokens you should be aware of their lifecycle as discussed in the docs here
In the oauthplayground you will see this
but on point 4 of the docs here it says this
Hmmm.
Also for reference see How do I authorise an app (web or installed) without user intervention? (canonical ?)
For applications that authenticate on behalf of themselves (i.e., to another application, traditionally by signing into a role account using a shared password), the OAuth2 alternative to ClientLogin offered by Google is Service Accounts:
https://developers.google.com/accounts/docs/OAuth2ServiceAccount