How to login using oauth in Springboot / Spring - spring-boot

We have one authservice that is running on different machine and this it provides oauth login.
So I need to write a client to get a access token. For that I wrote following piece of code. but its not working.
String polarisOauthURL = "https://test.com/auth/oauth/token";
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails ();
resourceDetails.setAccessTokenUri(polarisOauthURL);
resourceDetails.setClientId("test");
resourceDetails.setClientSecret("test");
resourceDetails.setGrantType("client_credentials");
List<String> scope = new ArrayList<>();
scope.add("read");
// scope.add("write");
resourceDetails.setScope(scope);
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
OAuth2RestTemplate oauthRestTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
List messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
oauthRestTemplate.setMessageConverters(messageConverters);
System.out.println("access token: " + oauthRestTemplate.getAccessToken());
when the last line getAccessToken executed it thows an following error.
error="access_denied", error_description="Error requesting access token."
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:145)
at org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider.obtainAccessToken(ClientCredentialsAccessTokenProvider.java:44)
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)
but when I am trying to the same thing from console then its working fine.
curl --user test:test --data 'grant_type=client_credentials' https://test.com/auth/oauth/token
Could someone help me how I can achieve this think in spring.
Thanks

I assume, that the code does send the client id and secret inside the body of the POST Request, whereas the curl command does use HTTP basic authentication wrapping those credentials base64 encoded inside an authorization header following the rules of HTTP basic auth. To ensure this in the code you might try to add something like this:
resourceDetails.setClientAuthenticationScheme(AuthenticationScheme.header);

Related

Spring Firebase cloud messaging connection Auth fails

I work with firebase for the first time and I am a bit confused about the usage of the cloud messaging.
Environment:
I have a Spring Microservice that should send messages ( data not notification) to apps by their token. ( platform independant)
As protocol I want to use the recommended Http v1.
I created a firebase account, added a test project und now I want to pust data there.
As far as I've read there is no way the see the message pushed for debugging?
I have no App to test the flow because it will be developed by externaly.
Current behaviour:
I just want to create a first test message. Therefor I use the following code.
// myProject from settings- general->ProjectID
String FIREBASE_API_URL = "https://fcm.googleapis.com/v1/projects/myProject/messages:send";
// From settings->cloud-messaging
String FIREBASE_SERVER_KEY = "newServerKey";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Authorization", "Bearer" + FIREBASE_SERVER_KEY);
httpHeaders.set("Content-Type", "application/json");
JSONObject json = new JSONObject();
JSONObject message = new JSONObject();
message.put("title","Hallo");
message.put("body","TEst");
json.put("data", message);
//I was hoping that this has not to be a valid token for testing.
json.put("to", "receiverFcmKey");
System.out.println("Sending :" + json.toString());
HttpEntity<String> httpEntity = new HttpEntity<>(json.toString(), httpHeaders);
for(int i =0; i<1; i++) {
System.out.println("Count:"+ i);
System.out.println(restTemplate.postForObject(FIREBASE_API_URL, httpEntity, String.class));
}
Here I get the error:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 Unauthorized: [no body]
Here I've read that I might be enableing the auth in my google apis settings.
QUESTION:
I don't know where I went wrong. Do i really have to enable the api first in the google settings?
Is the auth setting in the header wrong? ( I tried with blank after Bearer)
I thought the auth process will be done by the server key.
This is just a test environment setup and it would be enough to see that the auth process works and the messages are sent.

Jersey REST client post with authorization

I am using Jersey 1.9 in my Java Spring MVC web application. I am trying to make a post request for which I have to set two header values - authorization and content type. I was able to successfully make the post using postman REST client. I have tried many solutions found online, but the response I get is 401-Authorization failed. Following is the code is the code I use:
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource webResource = client.resource("https://api.constantcontact.com/v2/contacts?action_by=ACTION_BY_OWNER&api_key=tntkzy2drrmbwnhdv12s36vq");
WebResource.Builder builder = webResource.type(MediaType.APPLICATION_JSON);
builder.header(HttpHeaders.AUTHORIZATION, "Bearer 28ac08bc-58d5-426e-b811-3b1d1e505a9b");
ClientResponse responseMsg = webResource
.post(ClientResponse.class, jsonString);
responseMsg.getEntity(String.class);
Adding the postman screenshot:
After some research, I finally found what was missing in my case, based on the suggestions I got from the comments, I removed the query params from URL and added them as query params. ANd then added all query params to a multivalued map and used this multivalued map as the query param. My code was modified as follows:
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("action_by", "ACTION_BY_OWNER");
queryParams.add("api_key", apiKey);
WebResource webResource = client.resource(url);
ClientResponse responseMsg = webResource
.queryParams(queryParams)
.header("Content-Type", "application/json;charset=UTF-8")
.header("Authorization", "Bearer "+authorisationToken.trim())
.post(ClientResponse.class, jsonString);
responseMsg.getEntity(String.class);
Somehow when there are multiple query params, adding headers was not working, but when the params were added as a single multivalued map, everything works. Hope this helps someone.

Authenticating a Xamarin Android app using Azure Active Directory fails with 401 Unauthorzed

I am trying to Authenticate a Xamarin Android app using Azure Active Directory by following article here:
https://blog.xamarin.com/authenticate-xamarin-mobile-apps-using-azure-active-directory/
I have registered a native application with AAD; note that i havent given it any additional permissions beyond creating it.
Then i use the below code to authenticate the APP with AAD
button.Click += async (sender, args) =>
{
var authContext = new AuthenticationContext(commonAuthority);
if (authContext.TokenCache.Count > 0)
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().GetEnumerator().Current.Authority);
authResult = await authContext.AcquireTokenAsync(graphResourceUri, clientId, returnUri, new PlatformParameters(this));
SetContentView(Resource.Layout.Main);
doGET("https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/OPSLABRG/providers/Microsoft.Compute/virtualMachines/LABVM?api-version=2015-08-01", authResult.AccessToken);
};
private string doGET(string URI, String token)
{
Uri uri = new Uri(String.Format(URI));
// Create the request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
// Get the response
HttpWebResponse httpResponse = null;
try
{
httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (Exception ex)
{
Toast.MakeText(this, "Error from : " + uri + ": " + ex.Message, ToastLength.Long).Show();
return null;
}
}
This seems to be getting a token when using a Work account.
Using a valid hotmail account throws error A Bad Request was received.
However the main problem is when i try to retrieve VM details using REST.
the REST GET method fails with 401 Unauthorized error even when using the Work account.
I am not sure if the code is lacking something or if i need to give some additional permissions for the App. This needs to be able to support authenticating users from other tenants to get VM details.
Any guidance is appreciated.
note that i havent given it any additional permissions beyond creating
it.
This is the problem here.
In order for you to call the Azure Management API https://management.azure.com/, you must first register your application to have permissions to call this API.
You can do that as a part of your app registration like so:
Only at that point, will your app be authorized to call ARM, and your calls should start to work.
According to your description, I checked this issue on my side. As Shawn Tabrizi mentioned that you need to assign the delegated permission for accessing ARM Rest API. Here is my code snippet, you could refer to it:
var context = new AuthenticationContext($"https://login.windows.net/{tenantId}");
result = await context.AcquireTokenAsync(
"https://management.azure.com/"
, clientId, new Uri("{redirectUrl}"), platformParameter);
I would recommend you using Fiddler or Postman to simulate the request against ARM with the access_token to narrow this issue. If any errors, you could check the detailed response for troubleshooting the cause.
Here is my test for retrieving the basic information of my Azure VM:
Additionally, you could leverage jwt.io for decoding your access_token and check the related properties (e.g. aud, iss, etc.) as follows to narrow this issue.

PlatformPlugin exception getting app-only token using MSAL in ASP.NET Core

I'm trying to create an ASP.NET Core app that uses MSAL for the client credentials flow.
I get the following exception when trying to get an access token:
NullReferenceException: Object reference not set to an instance of an object.
Microsoft.Identity.Client.Internal.PlatformPlugin.LoadPlatformSpecificAssembly()
Authentication is modeled after this sample: active-directory-dotnet-webapp-openidconnect-aspnetcore-v2
Authorization is modeled after this sample: active-directory-dotnet-daemon-v2
My app is registered with the Mail.Read Application permission. Here's the code that throws the exception:
string authority = $"https://login.microsoftonline.com/{ tenantId }/v2.0";
ConfidentialClientApplication client = new ConfidentialClientApplication(
authority,
appId,
redirectUri,
new ClientCredential(appSecret),
null);//new TokenCache());
AuthenticationResult authResult = await client.AcquireTokenForClient(
new string[] { "Mail.Read" }, null);
return authResult.Token;
Also tried with "https://graph.microsoft.com/.default" scope, as in the daemon sample.
Answering this question. I opened this as an issue on the GitHub repo. It was closed with the following response:
this problem will not occur with the next release as we will move to a single binary.

Get request from browser works but using RestTemplate class I got 404 response for the same request

I can easily get the expected JSON response if I send the following get request from my browser:
http://www.bookandwalk.hu/api/AdminTransactionList?password=XXX&begindate=2016-04-30&enddate=2016-10-12&corpusid=HUBW
I tried to use SPRING BOOT 1.4 to create a small demo app to see how rest calls work in Spring.
So I created a POJO representing my domain object and I requested the list of domain objects by the following method invocation:
String startDate=new SimpleDateFormat("yyyy-MM-dd").format(start.getTime());
String endDate=new SimpleDateFormat("yyyy-MM-dd").format(end.getTime());
UriComponents uri=UriComponentsBuilder.newInstance().scheme("http").host("www.bookandwalk.hu").path("/api/AdminTransactionList").queryParam("password","xxx").queryParam("begindate",startDate).queryParam("enddate",endDate).queryParam("corpusid","HUBW").build().encode();
LOG.log(Level.INFO,"{0} were called as a rest call",uri.toString());
ResponseEntity<List<BandWTransaction>> transResponse =
restTemplate.exchange(uri.toString(),
HttpMethod.GET, null, new ParameterizedTypeReference<List<BandWTransaction>>() {
});
List<BandWTransaction> transactions = transResponse.getBody();
I got the following exception:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
As I logged the uri.toString(), I copied it to my browser to double check the is there any typos in my uri but it was working without any failure.
Does Anybody have idea why the same string works from the browser but not from the code?
It seems that you should specify a user agent header in the request for this webapp. Use a HttpEntity object to set this header.
final HttpHeaders headers = new HttpHeaders();
headers.set("User-Agent", "eltabo");
final HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<List<BandWTransaction>> transResponse =
restTemplate.exchange(uri.toString(),
HttpMethod.GET, entity,
new ParameterizedTypeReference<List<BandWTransaction>>() {});
Hope it helps.

Resources