Spring Boot basic authentication to 3rd party - java

I'm using Spring Boot to login to an external program using its basic authentication. That authentication exists of giving username + password and use Base64 to encode the header. After this I can use a call + header (containing password and username) to retrieve data.
Is there a simple way in Spring Boot to temporary save that header? And after the user is done, he/she can simply remove that header?
Otherwise the user has to keep giving username+password for every call to the API.
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
String url = "url";
RestTemplate template = new RestTemplate();
HttpHeaders headers = createHeaders("mail", "password");
ResponseEntity<JsonSearchResponse> response = template.exchange(url, HttpMethod.GET,
new HttpEntity<JsonSearchResponse>(headers), JsonSearchResponse.class);
JsonSearchResponse obj = response.getBody();
SpringApplication.run(DemoApplication.class, args);
}
public static HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}};
}
}
In the end I'm going to put this code in a different class. But just prototyping at the moment.
The application is going to be a web application. Using a database. I'm also going to use Thymeleaf.
All users use the same backend. As it is usually the case with web applications.

Related

Login into external Api and Post JSON to it

I am trying to make a post request to an external api that requires a username and password to be sent as headers. Currently the username and password are hardcoded. I want anyone to be able to login (with a account) and post the the api. I was wondering if there is a way to enable the browser native login prompt and use it for the api? Below is the code with the hardcoded username and password
public class RestService {
String Username="admin";
String Password="pass";
public String createPost() throws AuthenticateException,ClientHandlerException {
String url = "https://someapi.net/rest/api/2/issue/";
Client client = Client.create ();
client.addFilter (new HTTPBasicAuthFilter(Username, Password));
WebResource webResource= client.resource(url);
//--INPUT is formatted a bit different In my app but I just can't show it
String input = "{
"fields": {
"project":
{
"key": "TEST"
},
"summary": "REST ye merry gentlemen.",
"description": "Creating of an issue using project keys and issue type names using the REST API",
"issuetype": {
"name": "Bug"
}
}
}"
ClientResponse response = webResource.type("application/json").post(ClientResponse.class,input);
string output = response.getEntity(String.Class)
below is my controller
public class IndexController {
#Autowired
private RestService restService;
#GetMapping(value="/run")
public void test1() throws Exception{
restService.CreatePost();
}
}
Maybe simpler to use Spring REST Client - RestTemplate?
In your case
#Service
public class RestService {
public String createPost() {
final var restTemplate = new RestTemplate();
final var username = "admin";
final var password = "pass";
final var url = "https://someapi.net/rest/api/2/issue/";
var headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBasicAuth(username, password);
//header will look like 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' ('username:password' with Base64)
var fieldsFromInputObject = new FieldsFromInputObject();
fieldsFromInputObject.setSummary("REST ye merry gentlemen.");
//here set another fields
var inputObject = new InputObject();
inputObject.setFields(fields);
var request = new HttpEntity<>(inputObject, headers);
var response = restTemplate.postForObject(url, request, String.class);
//instead object you can use your serialized JSON
//last parameter determines a class of the response
}
}
About entering user's credentials: it's the very simple task and you can find plenty of links with this the simplest form and method controller which will handle these request parameters:
The Controller which contains the method with 2 parameters (of course, POST because GET requests non-secured)
Simple web-page with fields (native html, jsp, thymeleaf or others)
Configuration for your MVC application

Can I use Spring Boot to make requests using someone elses API?

Im new to Spring and im trying to understand it. Is it possible for me to use Spring boot to make calls to someone else's api? for example, the api im using needs to be authenticated using credentials they give me. I would like to use their API to make POST requests. So far I have found documents that relate to using your own API. These requests require headers to be passed as well.
Whats the simplest way I can do a POST request, passing my credentials and the required headers using Spring ?
Any help would be appreciated.
if i understand u well, u need to post another web-api with credentials okay you can use
restTemplate like the following example
public List<EtisAccount> getAllActiveAccount(){
logger.debug("Debug: in Class \t"+this.getClass().getName()+" Method Name is: \t"+new Object() {}.getClass().getEnclosingMethod().getName());
Properties sprinklrProp=sprinklrProperties.getSprinklrKeys();
SprinklrCredential sprinklrCredential=credentialBuilder.getSprinklrCredential();
RestTemplate restTemplate= new RestTemplate();
HttpHeaders header = new HttpHeaders();
header.setBearerAuth(sprinklrCredential.getAccess_token());
header.add("key", sprinklrCredential.getApi_key());
header.set("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
UriComponentsBuilder uriBuilder= UriComponentsBuilder.fromUriString(sprinklrProp.getProperty("sprinlrUri").toString())
.queryParam("types", sprinklrProp.getProperty("accountTypes").toString());
HttpEntity<String> entity= new HttpEntity<>(header);
sslCertificateValidation.disable();
ResponseEntity<String> sprinklrResponse=restTemplate.exchange(uriBuilder.toUriString(),HttpMethod.GET,entity, String.class);
List<EtisAccount> activeAccouts=etisAccountHelper.getAllSocialEtisAccounts(sprinklrResponse.getBody());
logger.debug(String.valueOf(sprinklrResponse.getStatusCodeValue()));
logger.debug(activeAccouts.toString());
return activeAccouts;
}
this is sample example for call online-API using RestTemplate
here i build header with credentials (bearer authentication)
HttpHeaders header = new HttpHeaders();
header.setBearerAuth(sprinklrCredential.getAccess_token());
header.add("key", sprinklrCredential.getApi_key());
header.set("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
and here i add header requestEntity to add to resttemplate request
HttpEntity<String> entity= new HttpEntity<>(header);
and here i get response using exchange method
ResponseEntity<String> sprinklrResponse=restTemplate.exchange(uriBuilder.toUriString(),HttpMethod.POST,entity, String.class);
You need following things :
Create a Spring web starter project from https://start.spring.io/
Create a new Java Class in your project and name it Controller. Add #RestController annotation to on class level.
Configure RestTemplate object in SpringBootApplication
Autowire that RestTemplate object in Controller class
Create a method in Controller class which using RestTemplate, will call the #PostMapping to their API.
You can try this way
This is the simple way to this
You can set user name and password as basic Auth
public class RESTInvoker {
private final String baseUrl;
private final String username;
private final String password;
public RESTInvoker(String baseUrl, String username, String password) {
this.baseUrl = baseUrl;
this.username = username;
this.password = password;
}
String getDataFromServer(String path) {
StringBuilder sb = new StringBuilder();
try {
URL url = new URL(baseUrl + path);
URLConnection urlConnection = setUsernamePassword(url);
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
return sb.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private URLConnection setUsernamePassword(URL url) throws IOException {
URLConnection urlConnection = url.openConnection();
String authString = username + ":" + password;
String authStringEnc = new String(Base64.encodeBase64(authString.getBytes()));
urlConnection.setRequestProperty("Authorization", "Basic " + authStringEnc);
return urlConnection;
}
}

Basic authentication for REST API using spring restTemplate

I am completely new in RestTemplate and basically in the REST APIs also. I want to retrieve some data in my application via Jira REST API, but getting back 401 Unauthorised. Found and article on jira rest api documentation but don't really know how to rewrite this into java as the example uses the command line way with curl. I would appreciate any suggestion or advice how to rewrite:
curl -D- -X GET -H "Authorization: Basic ZnJlZDpmcmVk" -H "Content-Type: application/json" "http://kelpie9:8081/rest/api/2/issue/QA-31"
into java using spring rest template. Where the ZnJlZDpmcmVk is a base64 encoded string of username:password. Thank you very much.
Taken from the example on this site, I think this would be the most natural way of doing it, by filling in the header value and passing the header to the template.
This is to fill in the header Authorization:
String plainCreds = "willie:p#ssword";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
And this is to pass the header to the REST template:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();
You may use spring-boot RestTemplateBuilder
#Bean
RestOperations rest(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.basicAuthentication("user", "password").build();
}
See documentation
(before SB 2.1.0 it was #basicAuthorization)
There are multiple ways to add the basic HTTP authentication to the RestTemplate.
1. For a single request
try {
// request url
String url = "https://jsonplaceholder.typicode.com/posts";
// create auth credentials
String authStr = "username:password";
String base64Creds = Base64.getEncoder().encodeToString(authStr.getBytes());
// create headers
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
// create request
HttpEntity request = new HttpEntity(headers);
// make a request
ResponseEntity<String> response = new RestTemplate().exchange(url, HttpMethod.GET, request, String.class);
// get JSON response
String json = response.getBody();
} catch (Exception ex) {
ex.printStackTrace();
}
If you are using Spring 5.1 or higher, it is no longer required to manually set the authorization header. Use headers.setBasicAuth() method instead:
// create headers
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");
2. For a group of requests
#Service
public class RestService {
private final RestTemplate restTemplate;
public RestService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder
.basicAuthentication("username", "password")
.build();
}
// use `restTemplate` instance here
}
3. For each and every request
#Bean
RestOperations restTemplateBuilder(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.basicAuthentication("username", "password").build();
}
I hope it helps!
As of Spring 5.1 you can use HttpHeaders.setBasicAuth
Create Basic Authorization header:
String username = "willie";
String password = ":p#ssword";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
...other headers goes here...
Pass the headers to the RestTemplate:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();
Documentation:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html#setBasicAuth-java.lang.String-java.lang.String-
(maybe) the easiest way without importing spring-boot.
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user", "password"));
Reference Spring Boot's TestRestTemplate implementation as follows:
https://github.com/spring-projects/spring-boot/blob/v1.2.2.RELEASE/spring-boot/src/main/java/org/springframework/boot/test/TestRestTemplate.java
Especially, see the addAuthentication() method as follows:
private void addAuthentication(String username, String password) {
if (username == null) {
return;
}
List<ClientHttpRequestInterceptor> interceptors = Collections
.<ClientHttpRequestInterceptor> singletonList(new BasicAuthorizationInterceptor(
username, password));
setRequestFactory(new InterceptingClientHttpRequestFactory(getRequestFactory(),
interceptors));
}
Similarly, you can make your own RestTemplate easily
by inheritance like TestRestTemplate as follows:
https://github.com/izeye/samples-spring-boot-branches/blob/rest-and-actuator-with-security/src/main/java/samples/springboot/util/BasicAuthRestTemplate.java
Instead of instantiating as follows:
TestRestTemplate restTemplate = new TestRestTemplate();
Just do it like this:
TestRestTemplate restTemplate = new TestRestTemplate(user, password);
It works for me, I hope it helps!
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
then continue with the same procedure mentioned by the others here:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
request, String.class);
Use setBasicAuth to define credentials
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("myUsername", myPassword);
Then create the request like you prefer.
Example:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
request, String.class);
String body = response.getBody();
I'm using spring version 5.3.15 for my unit test environment. I used withBasicAuth for my tests :
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTestClass {
...
#Autowired
private TestRestTemplate restTemplate;
...
#Test
#SneakyThrows
public void TestGetSettings(){
DtoClass dtoClass = this.restTemplate
.withBasicAuth(UserServices.DEFAULT_USER, UserServices.DEFAULT_PASSWORD)
.getForObject(String.format("http://localhost:%d/setting",
port), DtoClass.class);
assertThat(dtoClass.getClientAddress()).isNotEmpty();
}
...
}
As you see this method only work for basic authentication. If you look at the details of the withBasicAuth method, you will find that the method source will be like this:
// TestRestTemplate.java file:
...
public class TestRestTemplate {
...
private final RestTemplateBuilder builder;
...
public TestRestTemplate withBasicAuth(String username, String password) {
TestRestTemplate template = new TestRestTemplate(this.builder, username, password, this.httpClientOptions);
...
}
}
As a result, for other types of authentication you can use the RestTemplateBuilder as a builder which is mentioned in other answers.
Follow Step By Step
I added Client Credentials In application.Properties file like below...
http.basicauth.username = yourUserName
http.basicauth.password = yourPassword
And , Then I created one class With two fields Because I'm loading those two fields from the Application.Properties file : username and password . Make sure your class is annotated with #Component..
#Value("${http.basicauth.username}")
private String username;
#Value("${http.basicauth.password}")
private String password;
And Then , You need to autowired above class From Wherever you want..
// I'm getting a username and password from application.properties file
String userCredentials = referenceClassName.getUsername()+":"+referenceClassName.getPassword();
// Encoded User Credentials and Convert it into a String
String encodedUserCredentials= Base64.getMimeEncoder().encodeToString(userCredentialsBytes.getBytes());
headers.set("Authorization", "Basic " +base64UserCredentials);
HttpEntity request = new HttpEntity(headers);
String url = "externalUrl";
// Getting a Json String body
String body = restTemplate.exchange(url,HttpMethod.GET,request,String.class).getBody();
Note :: For getting an Access Token from String Json body , That's why I converted it into a Json Object
JsonObject tokenJsonObject = new JsonParser().parse(body).getAsJsonObject();
// Getting access token as string from tokenJsonObject
String accessToken = tokenJsonObject.has("access_token") && !tokenJsonObject.get("access_token").isJsonNull() ? tokenJsonObject.get("access_token").getAsString() : "";
If you have any concerns, please let me know in comments..Hope It will helpful to you..
I have been using Spring above 5.1.x
// create headers for basic auth
var headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

Spring Security, Rest Authentication and CSRF

I would like use authentication with my application.
I hava a Spring MVC app and Spring Security applied. Against browser, it is working fine.
It means, I authenticate a user to my app and use web page.
Now, I want to use rest. I added on my unsecure controller method #ResponseBody and I receive response in json.
But how to connect to my application with user and password with RestTemplate ?
My code in RestClient is (for test) :
public void unsecureProfileTest() {
String url = articleServiceUrl + "unsecure/profile/test.json";
url = articleServiceUrl + "secure/profile/wiew.json";
HttpEntity<Object> entity = new HttpEntity<Object>(getHeaders("user:userpassword"));
Object s = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
}
static HttpHeaders getHeaders(String auth) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON,
MediaType.TEXT_HTML));
byte[] encodedAuthorisation = Base64.encode(auth.getBytes());
headers.add("Authorization", "Basic "
+ new String(encodedAuthorisation));
return headers;
}
My SecurityConfig :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/*").permitAll().and()
.formLogin().successHandler(successHandler)
.defaultSuccessUrl("/").failureHandler(failureHandler)
.failureUrl("/login?error=true").permitAll().and().logout()
.permitAll();
http.authorizeRequests().antMatchers("/resources/**").permitAll();
http.authorizeRequests().antMatchers("/welcome").permitAll();
http.authorizeRequests().antMatchers("/unsecure/**").permitAll();
http.authorizeRequests().antMatchers("/secure/*").authenticated();
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
The result is : Access is denied.
I guess the problem comming from authentication from restTemplate but how can I authenticate ?
My second question is regarding csrf who is disabled but I want to enable it (my forms use it)
I'm using Spring 4.0 and Spring Security 3.2
EDIT
I updated my code with
String url = articleServiceUrl + "unsecure/profile/test.json";
url = articleServiceUrl + "secure/profile/wiew.json";
HttpEntity<Object> entity = new HttpEntity<Object>(getHeaders("{user:userpassword, password:userpassword}"));
Object s = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
I receive a code 302
EDIT 18022014 - 16:46
I updated to
String url = articleServiceUrl + "login?username=user&password=userpassword";
HttpEntity entity restTemplate;exchange(url, HTTPMethod.POST,null, HttpEntity.class)
system.out.println(entity);
In log of web server, I received a success message (see userdetails on "user").
Now, I would like use authentication to access to other url ("secure/profile/view.json")
How to keep authentication ?
Thank you
I have been playing with spring security and spring boot REST application and I created my own MapCsrfTokenRepository that I used instead of default HttpSessionCsrfTokenRepository.
Then you can enable csrf for your rest URIs with
http.csrf().csrfTokenRepository(tokenRepository)
The main idea is to return new CSRF_TOKEN when client access /login resource with GET, because no csrf token is needed for GET. And then client has to use this token in next calls.
Example is on github

Passing basic auth credentials with every request with HtmlUnit WebClient

I'm trying to write a simple smoke test for a web application.
The application normally uses form based authentication, but accepts basic auth as well, but since the default is form based authentication, it never sends an authentication required, but instead just sends the login form.
In the test I try to send the basic auth header using
WebClient webClient = new WebClient();
DefaultCredentialsProvider creds = new DefaultCredentialsProvider();
// Set some example credentials
creds.addCredentials("usr", "pwd");
// And now add the provider to the webClient instance
webClient.setCredentialsProvider(creds);
webClient.getPage("<some url>")
I also tried stuffing the credentials in a WebRequest object and passing that to the webClient.getPage method.
But on the server I don't get an authentication header. I suspect the WebClient only sends the authentication header if it get explicitly asked for it by the server, which never happens.
So the question is how can I make the WebClient send the Authentication header on every request, including the first one?
This might help:
WebClient.addRequestHeader(String name, String value)
More specific one can create an authentication header like this
private static void setCredentials(WebClient webClient)
{
String username = "user";
String password = "password";
String base64encodedUsernameAndPassword = base64Encode(username + ":" + password);
webClient.addRequestHeader("Authorization", "Basic " + base64encodedUsernameAndPassword);
}
private static String base64Encode(String stringToEncode)
{
return DatatypeConverter.printBase64Binary(stringToEncode.getBytes());
}

Categories