Twitter4j - Requests allotted via application-only auth for search/tweets - java

It is clearly mentioned that the number of Requests allotted via application-only auth for search/tweets is 450/15 minutes. I am using twitter4j version 4.0.1 but, I am getting only 180 requests/15 minutes via application-only auth.
I tried to get the limit using the code below and I got the limit as 450. But, am getting the rate limit exceeded error after 180 requests.
twitter.getRateLimitStatus().get("/search/tweets").getLimit();
Where did I go wrong?
Update
public static OAuth2Token getOAuth2Token(String key, String sec) {
OAuth2Token token = null;
ConfigurationBuilder cb;
cb = new ConfigurationBuilder();
cb.setApplicationOnlyAuthEnabled(true);
cb.setOAuthConsumerKey(key).setOAuthConsumerSecret(sec);
try
{
token = new TwitterFactory(cb.build()).getInstance().getOAuth2Token();
}
catch (Exception e)
{
System.out.println("Could not get OAuth2 token");
e.printStackTrace();
System.exit(0);
}
return token;
}
public TwitterManager() throws TwitterException {
OAuth2Token token;
token = getOAuth2Token("XXXX","XXXX");
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setApplicationOnlyAuthEnabled(true);
cb.setOAuthConsumerKey("XXXX");
cb.setOAuthConsumerSecret("XXXX");
cb.setOAuth2TokenType(token.getTokenType());
cb.setOAuth2AccessToken(token.getAccessToken());
twitter = new TwitterFactory(cb.build()).getInstance();
}
This is how I used application-only auth.

Are you able to share any more of your code?
From the results, I suspect you are not using application-only, but maybe have used another oauth flow?

Related

Are the Azure Workload Identity (Client Assertion) tokens compatible with the msal4j token cache?

I'm trying to use the Azure Workload Identity MSAL Java Sample, and I'm trying to figure out if the built-in token cache that comes with MSAL4J is actually usable with Azure Workload Identity (Client Assertions), as my understanding is that every time you request a new token, you need to read the AZURE_FEDERATED_TOKEN_FILE again (See // 1). I've looked through the MSAL4J code and to me it looks like you'd need to throw away the ConfidentialClientApplication (see // 2) and create a brand new one to load in a new federated token file, because the clientAssertion ends up baked into the client. So then I'd need to do my own checks to figure out if I need if I need to recreate the client, basically defeating the purpose of the built-in client.
Are my assumptions correct? Or is there some way to hook into the token refresh process and reload the clientAssertion?
Maybe MSAL4J needs integrated token cache support for Azure Workload Identity that handles the reloading of the client assertion on renewal?
Here is the sample code included for context.
public class CustomTokenCredential implements TokenCredential {
public Mono<AccessToken> getToken(TokenRequestContext request) {
Map<String, String> env = System.getenv();
String clientAssertion;
try {
clientAssertion = new String(Files.readAllBytes(Paths.get(env.get("AZURE_FEDERATED_TOKEN_FILE"))),
StandardCharsets.UTF_8); // 1
} catch (IOException e) {
throw new RuntimeException(e);
}
IClientCredential credential = ClientCredentialFactory.createFromClientAssertion(clientAssertion);
String authority = env.get("AZURE_AUTHORITY_HOST") + env.get("AZURE_TENANT_ID");
try {
ConfidentialClientApplication app = ConfidentialClientApplication
.builder(env.get("AZURE_CLIENT_ID"), credential).authority(authority).build(); // 2
Set<String> scopes = new HashSet<>();
for (String scope : request.getScopes())
scopes.add(scope);
ClientCredentialParameters parameters = ClientCredentialParameters.builder(scopes).build();
IAuthenticationResult result = app.acquireToken(parameters).join();
return Mono.just(
new AccessToken(result.accessToken(), result.expiresOnDate().toInstant().atOffset(ZoneOffset.UTC)));
} catch (Exception e) {
System.out.printf("Error creating client application: %s", e.getMessage());
System.exit(1);
}
return Mono.empty();
}
}

AssumeRoleResult not returning anything

I am trying to fetch temporary security credentials and use them to push/publish data on the Kinesis stream. Please check below code for obtaining credentials.
private AssumeRoleResult getAssumeRoleResult() {
AssumeRoleResult assumeRoleResult = null;
try {
log.info("Started to fetch AssumeRoleResult");
BasicSessionCredentials currentRoleCredentials = getCredentialsOfCurrentRole();
String sessionName = "assumedRole_" + RandomStringUtils.randomAlphanumeric(5).toUpperCase();
region = Config.getRegion();
AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(currentRoleCredentials)).withRegion(region)
.build();
String roleArn = Configurations.ROLE_ARN;
assumeRoleResult = sts.assumeRole(new AssumeRoleRequest().withRoleArn(roleArn)
.withDurationSeconds(AWS_KINESIS_SESSION_DURATION)
.withRoleSessionName(sessionName));
log.info("Your AssumeRoleResult is" + assumeRoleResult.toString())
return assumeRoleResult;
} catch(Exception e) {
log.error("Failed to get AssumeRoleResult with error : {}", e.getMessage());
e.printStackTrace();
}
}
private BasicSessionCredentials getCredentialsOfCurrentRole() throws JSONException {
// Code to fetch IAM credentials for current role
}
But when I checked the logs, found that assumeRoleResult is not returning anything.(I am not seeing any log saying "Your AssumeRoleResult is" and also not exception found).
Can you please let me know what what may be issue here.
To fix this issue I added following changes
Updated Trust relationship for given account
https://aws.amazon.com/blogs/security/how-to-use-trust-policies-with-iam-roles/
Updated aws-java-sdk-kinesis and aws-java-sdk-sts to latest version.

Cognito SRP Authentication JAVA SDK

Iam trying to authenticate a Java app with Cognito.
I have used for python the warrant library that worked very good. But i want to do the same in java now.
My Python function i used for authentication with the warrant library
def SRPauthentication(organizationAdmin,
password,
pool_id,
client_id,
client):
aws = AWSSRP(username=organizationAdmin,
password=password,
pool_id=pool_id,
client_id=client_id,
client=client)
tokens = aws.authenticate_user()
authorization_token= tokens['AuthenticationResult']['IdToken']
return authorization_token
with this i could easily acces some secured APIs.
Now i want to do the same with Java but i have problems.
This is my solution so far is this method:
public static void GetCreds()
{
AWSCognitoIdentityProvider identityProvider = AWSCognitoIdentityProviderClientBuilder.defaultClient();
AdminInitiateAuthRequest adminInitiateAuthRequest = new AdminInitiateAuthRequest().
withAuthFlow(AuthFlowType.USER_SRP_AUTH).
withClientId("234234234234").withUserPoolId("eu-central-1_sdfsdfdsf")
.addAuthParametersEntry("USERNAME", "UserK").
addAuthParametersEntry("PASSWORD","#######);
adminInitiateAuthRequest.getAuthFlow();
AdminInitiateAuthResult adminInitiateAuth = identityProvider.adminInitiateAuth(adminInitiateAuthRequest);
System.out.println(adminInitiateAuth.getAuthenticationResult().getIdToken());
}
When i run this i get an Exception:
Exception in thread "main" `com.amazonaws.services.cognitoidp.model.AWSCognitoIdentityProviderException: User: arn:aws:iam::XXXXXXXXXXXXXXXXX:user/khan is not authorized to perform: cognito-idp:AdminInitiateAuth on resource: arn:aws:cognito-idp:eu-central-1:XXXXXXXX:userpool/eu-central-1_XXXXXXX with an explicit deny (Service: AWSCognitoIdentityProvider; Status Code: 400; Error Code: AccessDeniedException; Request ID: 21be0b8e-adec-11e8-ad45-234234234)`
It says iam not authorized to perform this kind of instruction. So i guess iam doing something generally wrong. Because its working with my python code and in Java it recognizes my username from the credentials. The Cognito call should actually be independent from my aws credentials/useraccount right?
How to authenticate with Cognito using Java to get an Token to access secured aws services?
EDIT:
AWSCognitoIdentityProvider identityProvider = AWSCognitoIdentityProviderClientBuilder.standard()
.build();
InitiateAuthRequest adminInitiateAuthRequest = new InitiateAuthRequest()
.withAuthFlow(AuthFlowType.USER_SRP_AUTH)
.withClientId("XXXXXXXXXXXXXXXXX")
.addAuthParametersEntry("USERNAME", "user").
addAuthParametersEntry("PASSWORD","za$Lwn")
.addAuthParametersEntry("SRP_A",new AuthenticationHelper("eu-central-1XXXXXXXXX").getA().toString(16));
adminInitiateAuthRequest.getAuthFlow();
InitiateAuthResult adminInitiateAuth = identityProvider.initiateAuth(adminInitiateAuthRequest);
System.out.println(adminInitiateAuth);
I changed the AdminInitateAuthRequest to InitateAuthRequest. After that i had the Error missing SRP_A parameter that i somehow fixed with a similiar question here
And now i recive this :
{ChallengeName: PASSWORD_VERIFIER,ChallengeParameters: {SALT=877734234324234ed68300f39bc5b, SECRET_BLOCK=lrkwejrlewrjlewkjrewlrkjwerlewkjrewlrkjewrlkewjrlewkrjZ+Q==, USER_ID_FOR_SRP=user, USERNAME=user, SRP_B=43ecc1lwkerjwelrkjewlrjewrlkewjrpoipweoriwe9r873jr34h9r834hr3455f7d079d71e5012f1623ed54dd10b832792dafa3438cca3f59c0f462cbaee255d5b7c2werwerwerkjweorkjwerwerewrf5020e4f8b5452f3b89caef4a797456743602b80b5259261f90e52374adc06b456521a9026cce9c1cbe8b9ffd6040e8c1589d35546861422110ac7e38c1c93389b802a03e3e2e4a50e75d088275195f836f66e25f1a431dd56bb2},}
I have shorten the result with all the keys, but what to do next ?
Finally i could solve it with this code class.
There are multiple challenges involved in SRP authentication. The InitiateAuthRequest is one first request that is necessary.
This similiar question helped me :
stackoverflow
stackoverfow
String PerformSRPAuthentication(String username, String password) {
String authresult = null;
InitiateAuthRequest initiateAuthRequest = initiateUserSrpAuthRequest(username);
try {
AnonymousAWSCredentials awsCreds = new AnonymousAWSCredentials();
AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(Regions.fromName(this.region))
.build();
InitiateAuthResult initiateAuthResult = cognitoIdentityProvider.initiateAuth(initiateAuthRequest);
if (ChallengeNameType.PASSWORD_VERIFIER.toString().equals(initiateAuthResult.getChallengeName())) {
RespondToAuthChallengeRequest challengeRequest = userSrpAuthRequest(initiateAuthResult, password);
RespondToAuthChallengeResult result = cognitoIdentityProvider.respondToAuthChallenge(challengeRequest);
//System.out.println(result);
System.out.println(CognitoJWTParser.getPayload(result.getAuthenticationResult().getIdToken()));
authresult = result.getAuthenticationResult().getIdToken();
}
} catch (final Exception ex) {
System.out.println("Exception" + ex);
}
return authresult;
}
private InitiateAuthRequest initiateUserSrpAuthRequest(String username) {
InitiateAuthRequest initiateAuthRequest = new InitiateAuthRequest();
initiateAuthRequest.setAuthFlow(AuthFlowType.USER_SRP_AUTH);
initiateAuthRequest.setClientId(this.clientId);
//Only to be used if the pool contains the secret key.
//initiateAuthRequest.addAuthParametersEntry("SECRET_HASH", this.calculateSecretHash(this.clientId,this.secretKey,username));
initiateAuthRequest.addAuthParametersEntry("USERNAME", username);
initiateAuthRequest.addAuthParametersEntry("SRP_A", this.getA().toString(16));
return initiateAuthRequest;
}

How to access Twitter API resources using Twitter's Java library (twitter4j)

I'm new to Twitters API and Twitter's twitter4j library. I've recently registered an app to be able to use Twitter's API. Twitter has granted me consumer API keys (API key & API secret key), as well as an access token & access token secret.
The problem is, I've been trying to use twitter4j to authenticate into twitter (using the aforementioned keys), but when trying to access any of the APIs resources, I get an error saying I'm not allowed access due to a rate limit. But how can I possibly have reached a rate limit when I've never been able to query the api? :,(
This is what I'm attempting (with sensitive bits replaced by dummy values):
#SpringBootApplication
public class App
{
private static final String CONSUMER_KEY = "FakeConsumerKey";
private static final String CONSUMER_SECRET = "FakeConsumerSecret";
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
System.out.println("Making an authentication request to"
+ " retrieve the bearer token...");
OAuth2Token token;
token = getOAuth2Token();
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setApplicationOnlyAuthEnabled(true);
cb.setOAuthConsumerKey(CONSUMER_KEY);
cb.setOAuthConsumerSecret(CONSUMER_SECRET);
cb.setOAuth2TokenType(token.getTokenType());
cb.setOAuth2AccessToken(token.getAccessToken());
Twitter twitter = new TwitterFactory(cb.build()).getInstance();
try {
System.out.println("My screen name: " + twitter.getScreenName());
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static OAuth2Token getOAuth2Token()
{
OAuth2Token token = null;
ConfigurationBuilder cb;
cb = new ConfigurationBuilder();
cb.setApplicationOnlyAuthEnabled(true);
cb.setOAuthConsumerKey(CONSUMER_KEY);
cb.setOAuthConsumerSecret(CONSUMER_SECRET);
try
{
token = new TwitterFactory(cb.build())
.getInstance().getOAuth2Token();
System.out.println("token: " + token.getAccessToken());
}
catch (Exception e)
{
System.out.println("Can't get OAuth2 token");
e.printStackTrace();
System.exit(0);
}
return token;
}
}
This is the error returned:
403:The request is understood, but it has been refused. An accompanying error message will explain why. This code is used when requests are being denied due to update limits (https://support.twitter.com/articles/15364-about-twitter-limits-update-api-dm-and-following).
message - Your credentials do not allow access to this resource
code - 220
Relevant discussions can be found on the Internet at:
http://www.google.co.jp/search?q=9a9caf7a or
http://www.google.co.jp/search?q=bf94ba05
TwitterException{exceptionCode=[9a9caf7a-bf94ba05], statusCode=403, message=Your credentials do not allow access to this resource, code=220, retryAfter=-1, rateLimitStatus=null, version=4.0.6}
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:164)
at twitter4j.HttpClientBase.request(HttpClientBase.java:57)
at twitter4j.HttpClientBase.get(HttpClientBase.java:75)
at twitter4j.TwitterBaseImpl.fillInIDAndScreenName(TwitterBaseImpl.java:133)
at twitter4j.TwitterBaseImpl.fillInIDAndScreenName(TwitterBaseImpl.java:128)
at twitter4j.TwitterBaseImpl.getScreenName(TwitterBaseImpl.java:108)
at com.vismark.social.twitter.TwitterAccountService.App.main(App.java:41)
Where did I go wrong?
Definition of getScreenName
"Returns authenticating user's screen name.
This method may internally call verifyCredentials() on the first invocation if
- this instance is authenticated by Basic and email address is supplied instead of screen name, or - this instance is authenticated by OAuth."
User-based authentication has to use OAuth 1.0a not OAuth 2. You need to get access tokens, follow this :
https://developer.twitter.com/en/docs/basics/authentication/overview/using-oauth
When you get your access tokens, just update your ConfigurationBuilder like this :
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setApplicationOnlyAuthEnabled(false);
cb.setOAuthConsumerKey(CONSUMER_KEY)
.setOAuthConsumerSecret(CONSUMER_SECRET)
.setOAuthAccessToken(ACCESS_TOKEN)
.setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET);

Get tweets using Twitter4j

I have a java program for fetching my tweets and below is the code
public class TwitterTest {
public static void main(String[] args) {
Twitter twitter = new TwitterFactory().getInstance();
// My Applications Consumer and Auth Access Token
//twitter.setOAuthConsumer("67MIcbC1X6mbpaEqxa7YTd1hDPIdLb5bLKf4TxIRLAsX63DgFQ", "7HHjSHJ6Rjxx4ASC2465AlWBG");
twitter.setOAuthAccessToken(new AccessToken("s1y1iAhG5nsXTrE9OVAsqMtqiLIP4QKT8CmTRVgV9LC3O", "110445397-Cf3l9NAK4iD8VAERXp0ZMKnAfWx9KywuJs3OSdkF"));
try {
ResponseList<Status> a = twitter.getUserTimeline(new Paging(1,5));
for(Status b: a) {
System.out.println(b.getText());
}
}catch(Exception e ){
}
}
}
Below is the error which i get
Relevant discussions can be found on the Internet at:
http://www.google.co.jp/search?q=b64d2231 or
http://www.google.co.jp/search?q=309f0452
TwitterException{exceptionCode=[b64d2231-309f0452], statusCode=403, message=SSL is required, code=92, retryAfter=-1, rateLimitStatus=RateLimitStatusJSONImpl{remaining=178, limit=180, resetTimeInSeconds=1430935706, secondsUntilReset=775}, version=3.0.3}
What is the reason for the error?
You need to set SSL enabled. Look at this topic for further information: "SSL is required" exception while requesting OAuthRequest Token using Twitter4J library

Categories