I have recently started playing with the Bing Ads api for managing my ads and campaigns and I am having problem in authenticating user (not oauth authentication).
I authenticated my user using oauth by the following
private String devToken = "ZZZZZ";
private String clientId = "AAA0BBB-XXXX-AAAAA";
protected static String UserName = "a.v#h.c";
protected static String Password = "********";
// To get the initial access and refresh tokens you must call requestAccessAndRefreshTokens with the authorization redirection URL.
OAuthTokens tokens = oAuthDesktopMobileAuthCodeGrant.requestAccessAndRefreshTokens(url);
System.out.println("Access token: " + tokens.getAccessToken());
System.out.println("Refresh token: " + tokens.getRefreshToken());
authorizationData = new AuthorizationData();
authorizationData.setDeveloperToken(getDevToken());
authorizationData.setAuthentication(oAuthDesktopMobileAuthCodeGrant);
This authenticates my user just fine since I can use the ICustomerManagementService.class just fine for accounts related information
customerServiceClient = new ServiceClient<>(authorizationData, ICustomerManagementService.class);
ArrayOfAccount accounts = searchAccountsByUserId(user.getId());
The above works perfectly. But when I try to do the same with ICampaignManagementService.class like below
campaignServiceClient = new ServiceClient<>(authorizationData, ICampaignManagementService.class);
GetAdsByAdGroupIdRequest cReq = new GetAdsByAdGroupIdRequest();
cReq.setAdGroupId(1234567890L);
campaignServiceClient.getService().getAdsByAdGroupId(cReq);
I get error code 106 saying that the user is not authorized.
The user does not represent a authorized developer.
106
Any help in this regard ?
Please try to set the CustomerId and CustomerAccountId header elements (CustomerId and AccountId of AuthorizationData). These headers are not available with the Customer Management service, but are applicable for Campaign Management service. If that does not resolve the issue please feel free to send the SOAP request + response to support for investigation. I hope this helps!
Related
We've migrated from adal4j to msal4j in our java web applications.
All works well but the big difference is that when the user is already logged (maybe in other applications but same browser session) we always see the "select user" page and the user is not logged automatically and redirected to redirect uri as before with adal4j.
This is how we redirect to autentication page:
private static void redirectToAuthorizationEndpoint(IdentityContextAdapter contextAdapter) throws IOException {
final IdentityContextData context = contextAdapter.getContext();
final String state = UUID.randomUUID().toString();
final String nonce = UUID.randomUUID().toString();
context.setStateAndNonce(state, nonce);
contextAdapter.setContext(context);
final ConfidentialClientApplication client = getConfidentialClientInstance();
AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
.builder(props.getProperty("aad.redirectURI"), Collections.singleton(props.getProperty("aad.scopes"))).responseMode(ResponseMode.QUERY)
.prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
contextAdapter.redirectUser(authorizeUrl);
}
I've tried to remove .prompt(Prompt.SELECT_ACCOUNT)
but I receive an error
Any ideas?
• You might be getting the option for selecting the user account after switching to MSAL4J in your browser even after the SSO is enabled because either clearing the token cache is enabled in your code or MsalInteractionRequiredException option is thrown and specified accordingly due to which the application asks for a token interactively.
Thus, please check which accounts information is stored in the cache as below: -
ConfidentialClientApplication pca = new ConfidentialClientApplication.Builder(
labResponse.getAppId()).
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
build();
Set<IAccount> accounts = pca.getAccounts().join(); ’
Then, from the above information, if you want to remove the accounts whose prompts you don’t want to see during the user account selection such that the default account should get selected and signed in automatically, execute the below code by modifying the required information: -
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
• And for the MsalInteractiveRequiredException class in the code, kindly refer to the below official documentation link for the AcquireTokenSilently and other reasons responsible for the behaviour. Also, refer to the sample code given below for your reference regarding the same: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-error-handling-java#msalinteractionrequiredexception
IAuthenticationResult result;
try {
ConfidentialClientApplication application =
ConfidentialClientApplication
.builder("clientId")
.b2cAuthority("authority")
.build();
SilentParameters parameters = SilentParameters
.builder(Collections.singleton("scope"))
.build();
result = application.acquireTokenSilently(parameters).join();
}
catch (Exception ex){
if(ex instanceof MsalInteractionRequiredException){
// AcquireToken by either AuthorizationCodeParameters or DeviceCodeParameters
} else{
// Log and handle exception accordingly
}
}
I have a problem for a backend solution developpement. I need someone to guide me.
I'm developping a backend solution with SpringBoot.
My backend should :
Connect to an Active Directory
Use a token system for the security part
Give special access for each request (based on AD group)
After a lot of tests and research, I already have this :
Connect to an Active Directory
For the connection to AD part, I did this :
Inside a class that extends WebSecurityConfigurerAdapter
#Override
public void configure(AuthenticationManagerBuilder auth) {
ActiveDirectoryLdapAuthenticationProvider adProvider
= new ActiveDirectoryLdapAuthenticationProvider("domain.com", "ldap", "ou,dc");
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
adProvider.setUserDetailsContextMapper(userDetailsContextMapper());
auth.authenticationProvider(adProvider);
}
userDetailsContextMapper() simply maps the info to an user class that contains the username, the lastname and the list memberOf of the user (AD groups).
Using token
I use this method for the token. It works too.
public SignedJWT getToken(String username) {
JWSSigner signer = null;
SecureRandom random = new SecureRandom();
byte[] sharedSecret = new byte[32];
random.nextBytes(sharedSecret);
signer = new MACSigner(sharedSecret);
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject(username)
.issuer("domain")
.expirationTime(new Date(new Date().getTime() + 60 * 1000))
.build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
signedJWT.sign(signer);
String serializedToken = signedJWT.serialize();
return signedJWT;
}
Access per request
For the third part I want to give access to a specific request only for a given AD group.
Imagine I have two correctly mapped request :
domain.com/sales/2022/all : Return all the sales values for the year 2022
domain.com/IT/inventory/all: Return all the IT inventory
I want only the people that are from the group IT that can get a result from the IT's request and for the sale's request, only someone who is a member of the groupe sales.
But first of all, I want only people who are authenticated and have a valid token who can call a request.
I searched and tested different solutions on the internet but I did not find anything compatible with my two previous method.
Can you help me ? I'm not specially looking for a solution, a link to a good documentation or some example are enough for me.
I am trying to access emails on a Office365 mailbox, using Exchange Web Services (EWS).
My O365 admin has created :
the shared mailbox : shared#domain.com
the account : my.account#domain.com
a group, giving access to the account on the mailbox
I am able to retrieve the Oauth token using the appId/tenantId and a UserNamePasswordParameters using the account's credentials, and now I am trying to retrieve the emails from the mailbox, but I get this error :
microsoft.exchange.webservices.data.core.exception.service.remote.ServiceResponseException:
Mailbox does not exist.
here's my code :
public Iterable fetchEmails(String token, String account) throws Exception {
if(token==null) {
token = getToken();
}
FindItemsResults<Item> emails;
try (ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2)) {
service.getHttpHeaders().put("Authorization", "Bearer " + token);
service.setUrl(new URI("https://outlook.office365.com/EWS/Exchange.asmx"));
service.setWebProxy(new WebProxy(PROXY_HOST, PROXY_PORT));
FolderId folder = new FolderId(WellKnownFolderName.Inbox, new Mailbox(account));
emails = service.findItems(folder, new ItemView(15));
}
return emails;
}
OK, it was a bit stupid.. I got confused because the account is also an email..
solution is to pass the mailbox (shared#domain.com) instead of the account (my.account#domain.com) when building the Mailbox object :
FolderId folder = new FolderId(WellKnownFolderName.Inbox, new Mailbox("shared#domain.com"));
And now it's working, I am able to get the emails.
I'm trying to authenticate in Vimeo using Scribe. It's not going over too well. I keep getting error code 100 back, but it still gives me an Authorization URL and when I go to it I'm able to grant access. It's just when I enter the authorization code in and try to trade the request token for an access token it doesn't work. I'm using the Facebook example and tweaking it to work with Vimeo. I don't really know what I'm doing here. I asked a question earlier and was told that I need to include apache commons codec on my classpath. Well, I included it in my environment variables and that didn't change anything. So I just added it to my libraries for the project and that seemed to get me a step farther. Now I just have no idea what to do from here. I don't understand why I'm getting this. Here's my code and output:
public class VimeoTest
{
private static final String NETWORK_NAME = "Vimeo";
private static final Token EMPTY_TOKEN = null;
public static void main(String[] args)
{
// Replace these with your own api key and secret
String apiKey = "MYAPIKEY";
String apiSecret = "MYAPISECRET";
OAuthService service = new ServiceBuilder()
.provider(VimeoApi.class)
.apiKey(apiKey)
.apiSecret(apiSecret)
.debug()
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
OAuthRequest orequest = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
orequest.addQuerystringParameter("method", "vimeo.test.null");
Response send = orequest.send();
System.out.println(send.getBody());
// Obtain the Authorization URL
System.out.println("Fetching the Authorization URL...");
Token requestToken = service.getRequestToken();
String authorizationUrl = service.getAuthorizationUrl(requestToken);
System.out.println("Got the Authorization URL!");
System.out.println("Now go and authorize Scribe here:");
//I do NOT want to have to do this. Is there any other way I can have this authorize without going to a web browser to do this?
System.out.println(authorizationUrl);
System.out.println("And paste the authorization code here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
//****Breaks on the line above.****
//I think it's because the orequest.send() returned a 100 error code
//Note, EMPTY_TOKEN is declared as null, but I think that's ok. Verifier is not null.
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println();
Here's the output:
=== Vimeo's OAuth Workflow ===
1.0
<?xml version="1.0" encoding="utf-8"?>
<rsp generated_in="0.0033" stat="fail">
<err code="100" expl="The API key passed was not valid" msg="Invalid API Key" />
</rsp>
Fetching the Authorization URL...
obtaining request token from http://vimeo.com/oauth/request_token
setting oauth_callback to oob
generating signature...
base string is: POST&http%3A%2F%2Fvimeo.com%2Foauth%2Frequest_token&oauth_callback%3Doob%26oauth_consumer_key%3DACONSUMERKEY%26oauth_nonce%3D2861480766%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1331941401%26oauth_version%3D1.0
signature is: 7H/C4F4rK0FYZ5oZGf76Rl8P8yQ=
appended additional OAuth parameters: { oauth_callback -> oob , oauth_signature -> 7H/C4F4rK0FYZ5oZGf76Rl8P8yQ= , oauth_version -> 1.0 , oauth_nonce -> 2861480766 , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> ACONSUMERKEY , oauth_timestamp -> 1331941401 }
using Http Header signature
sending request...
response status code: 200
response body: oauth_token=bf3da4ec799559c9f8b1f8bda2b8d6ee&oauth_token_secret=AOAUTHTOEKN SECRET&oauth_callback_confirmed=true
Got the Authorization URL!
Now go and authorize Scribe here:
http://vimeo.com/oauth/authorize?oauth_token=bf3da4ec799559c9f8b1f8bda2b8d6ee
And paste the authorization code here
>>unicorn-duqx0
Exception in thread "main" java.lang.NullPointerException
Trading the Request Token for an Access Token...
obtaining access token from http://vimeo.com/oauth/access_token
at org.scribe.oauth.OAuth10aServiceImpl.getAccessToken(OAuth10aServiceImpl.java:75)
at autouploadermodel.VimeoTest.main(VimeoTest.java:51)
Java Result: 1
BUILD SUCCESSFUL (total time: 27 seconds)
Edit: added .debug() to new ServiceBuilder() and updated the output accordingly.
Change this line:
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
For:
Token accessToken = service.getAccessToken(requestToken, verifier);
Edit
The whole key unauthorized part is because this piece of code:
OAuthRequest orequest = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
orequest.addQuerystringParameter("method", "vimeo.test.null");
Response send = orequest.send();
System.out.println(send.getBody());
You're trying to make a GET request to the api root (not sure even if this is a valid resource) without signing it. Of course it's going to yield an unauthorized error.
I get the error
com.google.gdata.util.AuthenticationException: Unknown authorization header
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:600) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:552) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535) ~[gdata-core-1.0.jar:na]
when trying to access the Google Calendar data via their API.
Here is what happens before that error.
1) I authenticate with Google:
final AccessTokenResponse response =
new GoogleAuthorizationCodeGrant(httpTransport,
jsonFactory,
clientId, clientSecret, authorizationCode,
redirectUrl).execute();
final GoogleAccessProtectedResource accessProtectedResource =
new GoogleAccessProtectedResource(
response.accessToken, httpTransport, jsonFactory,
clientId, clientSecret,
response.refreshToken);
LOGGER.debug("response.accessToken: {}", response.accessToken);
this.oauthAccessToken = response.accessToken;
...
2) I read some data via the tasks API:
this.service =
new Tasks(httpTransport, accessProtectedResource,
jsonFactory);
this.service.setApplicationName(this.applicationName);
This seems to work.
3) Then I try to read data from the Google Calendar API:
final OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
final GoogleOAuthParameters oauth = new GoogleOAuthParameters ();
oauth.setOAuthConsumerKey("myapp.com");
oauth.setOAuthConsumerSecret(CLIENT_SECRET); // Client secret from "Google API access" page, "Client secret" entry
oauth.setOAuthToken(this.oauthAccessToken); // Access token from step 1
oauth.setOAuthTokenSecret(aAuthorizationCode);
// aAuthorizationCode is taken from the callback URL.
// For http://myapp.com/oauth2callback?code=4/uy8Arb4bhRPwWYSr3QwKPt9lIZkt
// aAuthorizationCode is equal to "4/uy8Arb4bhRPwWYSr3QwKPt9lIZkt" (without quotes)
oauth.setScope(SCOPE_CALENDAR); // https://www.google.com/calendar/feeds/
final CalendarService calendarService =
new CalendarService(APPLICATION_NAME);
calendarService
.setOAuthCredentials(oauth, signer);
LOGGER.debug("calendarService: {}", calendarService);
final URL feedUrl =
new URL(
"http://www.google.com/calendar/feeds/default/allcalendars/full");
final CalendarFeed resultFeed =
calendarService.getFeed(feedUrl, CalendarFeed.class);
At the last line (calendarService.getFeed...) the aforementioned exception occurs.
I have following questions:
1) Is my call
oauth.setOAuthConsumerKey
correct?
I. e. is the "consumer key" equal to "Product name" in the Google API console, or to "Client ID" field (value is something like 42912397129473.apps.googleusercontent.com)
2) Is the setOAuthTokenSecret correct? I. e. is it the code that I get, when Google redirects the user back to my app?
3) If questions 2 and 3 were answered with yes, what else can be the cause of my problem?
Thanks
Dmitri
P. S.: Previously, I could access Google calendar with simple access (i. e. with Google user name and password). However, this is not an option now because users of my app will not want to give away their Google password.
Finally, I solved my problem by following the example at
http://code.google.com/p/gdata-java-client/source/browse/trunk/java/sample/oauth/OAuthExample.java
My advice to all future victims^W users of OAuth: Pay attention to the smallest details in the OAuth tutorials. The OAuth devil lies in details.