How to pass Spotify access token retrieved by Spring controller? - java

I am using Spotify web API to get access to user data:
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
final String clientId = "clientId";
final String clientSecret = "clientSecret";
final String redirectURI = "http://localhost:8080/callback/";
final Api api = Api.builder()
.clientId(clientId)
.clientSecret(clientSecret)
.redirectURI(redirectURI)
.build();
/* Set the necessary scopes that the application will need from the user */
final List<String> scopes = Arrays.asList("user-read-private", "user-read-email");
/* Set a state. This is used to prevent cross site request forgeries. */
final String state = "someExpectedStateString";
String authorizeURL = api.createAuthorizeURL(scopes, state);
/* Here connecting to authorizeURL */
}
}
Then I connect to authorizeUrl and get the access token (code) from redirectUri which looks like this: localhost:8080/callback/?code=123
I can get the code and display it using Spring controller in my localhost:
#RestController
public class TokenController {
private static final String template = "Your Spotify acces code: %s";
#RequestMapping("/callback/")
public Token tokenValue(#RequestParam(value="code", defaultValue="Spotify access code") String value) {
return new Token(String.format(template, value));
}
}
How do I pass this code back to my Application so that I can finish the process of authorization?

I initially stored it within the http server and then polled the http server from my application by another API method. Very clunky and potentially insecure.
A later solution was to embed some lightweight http server classes within my application. This allowed me to simply read some class variables. It took quite a lot of integration but the solution is quite clean. It seems a lot of code for one value.
I'm still not happy with this but it will do for now.

Related

Jira REST API with proxy (Java)

I would like to use the Jira REST Client API for Java in an application that needs to go through a proxy to access the desired Jira instance. Unfortunately I didn't find a way to set it when using the given factory from that library:
JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
String authentication = Base64.getEncoder().encodeToString("username:password".toBytes());
return factory.createWithAuthenticationHandler(URI.create(JIRA_URL), new BasicAuthenticationHandler(authentication));
How can we use the Jira API and set a proxy ?
The only solution I found on the internet was to set it with system parameters (see solution 1 below). Unfortunately that did not fit my requirements as in the company I work for, there are multiple proxies and depending on the service to call, it has to use another proxy configuration. In that case, I cannot set the system properties without destroying all calls to other services that would need another proxy.
Nevertheless, I was able to find a way to set it by re-implementing some classes (see solution 2).
Important limitation: the proxy server must not ask for credentials.
Context
Maybe as context before, I created a class containing proxy configuration:
#Data
#AllArgsConstructor
public class ProxyConfiguration {
public static final Pattern PROXY_PATTERN = Pattern.compile("(https?):\\/\\/(.*):(\\d+)");
private String scheme;
private String host;
private Integer port;
public static ProxyConfiguration fromPath(String path) {
Matcher matcher = PROXY_PATTERN.matcher(path);
if (matcher.find()) {
return new ProxyConfiguration(matcher.group(1), matcher.group(2), toInt(matcher.group(3)));
}
return null;
}
public String getPath() {
return scheme + "://" + host + ":" + port;
}
}
Set system properties for proxy
Call the following method with your proxy configuration at the start of the application or before using the Jira REST API:
public static void configureProxy(ProxyConfiguration proxy) {
if (proxy != null) {
System.getProperties().setProperty("http.proxyHost", proxy.getHost());
System.getProperties().setProperty("http.proxyPort", proxy.getPort().toString());
System.getProperties().setProperty("https.proxyHost", proxy.getHost());
System.getProperties().setProperty("https.proxyPort", proxy.getPort().toString());
}
}
Re-implement AsynchronousHttpClientFactory
Unfortunately, as this class has many private inner classes and methods, you will have to do an ugly copy paste and change the following code to give the wanted proxy configuration:
public DisposableHttpClient createClient(URI serverUri, ProxyConfiguration proxy, AuthenticationHandler authenticationHandler) {
HttpClientOptions options = new HttpClientOptions();
if (proxy != null) {
options.setProxyOptions(new ProxyOptions.ProxyOptionsBuilder()
.withProxy(HTTP, new Host(proxy.getHost(), proxy.getPort()))
.withProxy(HTTPS, new Host(proxy.getHost(), proxy.getPort()))
.build());
}
DefaultHttpClientFactory<?> defaultHttpClientFactory = ...
}
You can then use it (in the following example, my re-implementation of AsynchronousHttpClientFactory is called AtlassianHttpClientFactory):
URI url = URI.create(JIRA_URL);
String authentication = Base64.getEncoder().encodeToString("username:password".toBytes());
DisposableHttpClient client = new AtlassianHttpClientFactory().createClient(url, proxy, new BasicAuthenticationHandler(authentication));
return new AsynchronousJiraRestClient(url, client);
Note that after all those problems, I also decided to write a Jira client library supporting authentication, proxy, multiple HTTP clients and working asynchronously with CompletableFuture.

Create unique user for each test class run executing automation test

I have implemented parallel testing using Selenium and TestNG for a web application, however, my webapp got a restriction where only one session can be handled at the time (it is not supporting multi-sessions, when you login with the same user it will disconnect your older session), the solution of which I have thought to solve it is to create a unique user for each test (using API), so I have implemented it but when I am running the tests in parallel (using testng.xml file with thread-count="2") I am creating the same user twice! with the same credentials, I want to be able to create a unique user where it will create one unique user for each run.
This is my code:
public class BaseApiTest extends BaseTest {
protected String token;
protected String CREATED_ADMIN_TEST_USER;
protected String CREATED_ADMIN_TEST_PASSWORD;
private static final AtomicReference<String> ACCESS_TOKEN = new AtomicReference<>();
#BeforeClass(alwaysRun=true)
public void baseApiSetup() throws InterruptedException, ApiException {
generateToken();
createAdminUser();
}
private void generateToken() {
........
..........
...........
token = "Bearer " + ACCESS_TOKEN.get();
context.setAttribute("api-key", token);
context.setAttribute("HOST", HOST);
T_Logger.info("Host url address is: =[{}]", HOST);
T_Logger.info("new api key token =[{}]", token);
}
private void createAdminUser() throws ApiException, InterruptedException {
UsersAPIUnitTest usersAPITU = new UsersAPIUnitTest(context);
usersAPITU.createUser();
CREATED_ADMIN_TEST_USER = UsersAPIUnitTest.getEmail();
CREATED_ADMIN_TEST_PASSWORD = UsersAPIUnitTest.getPassword();
}
}
and this is used by the login page with the newly created user:
protected void adminSignIn() {
loginPage.login(CREATED_ADMIN_TEST_USER, CREATED_ADMIN_TEST_PASSWORD, true);
writeToLoggerSignIn(CREATED_ADMIN_TEST_USER);
}
and then I am starting to run my tests.
Expected: each test class will contain its own unique user
Actual: all the users that are being created are the same user with the same credentials
========================EDIT===============================
This is how I create new user:
public String createUserCms(String name, String email, String phone, String password) throws ApiException {
NewUserPayload body = new NewUserPayload();
body.setStatus(true);
body.setName(name);
body.setEmail(email);
body.setPhone(phone);
body.setPassword(password);
body.setPasswordConfirmation(password);
printBody(body);
return usersApi.createUser(token, body);
}
I have been working on a generic solution for this problem so that all automation teams can use it, still work in progress. I'm sure you would have explored other options, but creating users every time you run a test is not a good idea, rather you have to create the users once and use them otherwise you end up adding more users into your system (if you are cleaning up the users #afterMethod that's fine)
But for now, in your case, you have to make sure that you pass a unique name/email when creating the user and return that username/email address.
If you can share your createUser method snippet, we can help you more.

Fortify Scan issue (XSS) Cross site scripting Reflected - method sends unvalidated data to webbrowser

I am getting the Fortify error which says that Method sends unvalidated data to a web browser which can result browser executing malicious code.
This is a java web application using spring framework.
Controller class :
public class Controller {
#Autowired
public Server server;
#Autowired
public Service xxxservice;
#RequestMapping("\path1\serverId\")
#ResponseBody
public String openFile(....) {
List<FilePath> filePath= getFilePaths(server, form.getPaths.values);
FileResultResponse response = xxxservice.openFile(server, getAbsolutePath(filePath);
String jsonOutput = getOutput(response,filePath);
return jsonOutput;
Server.java
class Server {
String serverName;
String serverDescription;
int serverId;
String serverAddress;
List<String> rootDirectories;
public void setServerName() {
this.serverName = serverName;
All the setter methods are available for the above class.
The report throws the error at getOutput method line saying that server.setName, server.setRootDirectories, etc should be validated before sending data to web browser.
The server values are set through some initialization method inside getFilePaths() method as below
public void initialization(server,root) {
this.server=server;
this.root=root;
How these server values should be validated to rectify the Fortify scan issue ?
As you are not dealing with byte arrays as in my case , probably you could try using
Jsoup.clean(filePath,Whitelist.basic());
This solved most of my issues except for the case where I need to write pdf from a byte array.

Facebook4j - get access and post to different groups

I have a question regarding facebook4j API for Java.
I would like to have the following:
- I have a webapp with different user
- Each user can post with his Facebook Account to different groups
- This means I have to store from every user the different API Keys
- The Key should not expire, is this possible?
Here a sample code for get access:
public class LoginFacebook {
public static String appId = "myAppId"; // Sample values
public static String appSecret = "myAppSecret";
public static String access_token = "myToken";
public static Facebook facebook;
public RecuperationFacebook() {
facebook = new FacebookFactory().getInstance();
facebook.setOAuthAppId(appId, appSecret);
facebook.setOAuthAccessToken(new AccessToken(access_token));
}
public static Comment Commentaire(String id_comment) throws FacebookException {
Comment commentaire =facebook.getComment(id_comment, null);
return(commentaire);
}
}
Question:
- How get every user his API Key?
- What are the different API Keys? (appId, appSecret, access_token) ?
Many thanks for help

Creating input parameters and using java web service function in ASP.NET Web API

I have created a java web service that does addition function. I also have created an ASP.NET Web API which calls the java web service and displays the result. Lets say i typed in http://localhost:8080/addition/9/6 as the URL with input parameters that the java web service function should add. I get the output data as {"firstNumber":9,"secondNumber":6,"sum":15}. When i run my ASP.NET Web API, i will be redirected to http://localhost:55223/ and i will get the output data as {"firstNumber":9,"secondNumber":6,"sum":15}.
Right now, what i want to do is, when i run my ASP.NET Web API, i should be able to input parameters in the URL of the ASP.NET Web API (http://localhost:55223/addition/9/6) and instead of displaying result straight from Java web service, i want to use the function of the java web service in my API to calculate the sum of the input parameters. Does anyone have an idea on how can i go about doing that? What are the changes that i should make in my codes?
Here are my codes:
ASP.NET Web API codes
RestfulClient.cs
public class RestfulClient
{
private static HttpClient client;
private static string BASE_URL = "http://localhost:8080/";
static RestfulClient()
{
client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> addition(int firstNumber, int secondNumber)
{
try
{
var endpoint = string.Format("addition/{0}/{1}", firstNumber, secondNumber);
var response = await client.GetAsync(endpoint);
return await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
HttpContext.Current.Server.Transfer("ErrorPage.html");
}
return null;
}
}
ApiController.cs
public class ApiController : Controller
{
private RestfulClient restfulClient = new RestfulClient();
public async Task<ActionResult> Index()
{
int firstNumber = 9;
int secondNumber = 6;
var result = await restfulClient.addition(firstNumber, secondNumber);
return Content(result);
}
}
Java web service codes
AdditionController.java
#RestController
public class AdditionController {
private static final String template = " %s";
private static int getSum;
#RequestMapping("/addition/{param1}/{param2}")
#ResponseBody
public Addition addition
(#PathVariable("param1") int firstNumber,#PathVariable("param2") int secondNumber) {
return new Addition(
(String.format(template, firstNumber)), String.format(template, secondNumber));
}
}
Someone please help me thank you so much in advance.
what i want to do is, when i run my ASP.NET Web API, i should be able to input parameters in the URL of the ASP.NET Web API (http://localhost:55223/addition/9/6)
Web API uses many conventions and if you play nicely then things work pretty well. The first thing you need to do is to rename your controller like this:
public class AdditionController : ApiController
{
public async Task<IHttpActionResult> Get(int firstNumber, int secondNumber)
{
var result = await restfulClient.addition(firstNumber, secondNumber);
return Ok(result);
}
}
You will notice a few things in above code:
The controller is called AdditionController. When you type addition in the url, the routing engine will look for a controller named Addition + the word Controller.
It inherits ApiController not Controller.
It has a Get action. If you make a GET request, the API routing engine will search for an action named Get or starting with Get. Thus it will find this action.
The action is returning IHttpActionResult. See my answer here for why.
It uses the extension method named Ok to return an HTTP Status code of 200. This is to follow good restful guidelines and HTTP guidelines.
You can call the above like this:
http://localhost:55223/addition?firstNumber=1&secondNumber=6
If you want to be able to call it like this:
http://localhost:55223/addition/9/6
Then you need to make some changes to the WebApiConfig class. Add this to code before the code for DefaultApi:
config.Routes.MapHttpRoute(
name: "AdditionApi",
routeTemplate: "api/addition/{firstNumber}/{secondNumber}",
defaults: new { action = "Get", controller = "Addition" }
);
Above we are telling the routing engine: Hey routing engine, if the url contains the word api/addition followed by a variable and another variable, then use the Get method of the Addition controller*.

Categories