I'm working with a Spring Boot + Spring Security OAuth2 to consume the Restful Oauth2 service.
Our Oauth2 service is always expects HTTP GET But OAuth2AccessTokenSupport always sending HTTP POST.
Result:
resulted in 405 (Method Not Allowed); invoking error handler
protected OAuth2AccessToken retrieveToken(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) throws OAuth2AccessDeniedException {
try {
this.authenticationHandler.authenticateTokenRequest(resource, form, headers);
this.tokenRequestEnhancer.enhance(request, resource, form, headers);
AccessTokenRequest copy = request;
ResponseExtractor delegate = getResponseExtractor();
ResponseExtractor extractor = new ResponseExtractor(copy, delegate) {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().containsKey("Set-Cookie")) {
this.val$copy.setCookie(response.getHeaders().getFirst("Set-Cookie"));
}
return ((OAuth2AccessToken) this.val$delegate.extractData(response));
}
};
return ((OAuth2AccessToken) getRestTemplate().execute(getAccessTokenUri(resource, form), getHttpMethod(),
getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()));
} catch (OAuth2Exception oe) {
throw new OAuth2AccessDeniedException("Access token denied.", resource, oe);
} catch (RestClientException rce) {
throw new OAuth2AccessDeniedException("Error requesting access token.", resource, rce);
}
}
<b>protected HttpMethod getHttpMethod() {
return HttpMethod.POST;
}</b>
protected String getAccessTokenUri(OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) {
String accessTokenUri = resource.getAccessTokenUri();
if (this.logger.isDebugEnabled()) {
this.logger.debug(new StringBuilder().append("Retrieving token from ").append(accessTokenUri).toString());
}
StringBuilder builder = new StringBuilder(accessTokenUri);
String separator;
if (getHttpMethod() == HttpMethod.GET) {
separator = "?";
if (accessTokenUri.contains("?")) {
separator = "&";
}
for (String key : form.keySet()) {
builder.append(separator);
builder.append(new StringBuilder().append(key).append("={").append(key).append("}").toString());
separator = "&";
}
}
return builder.toString();
}
Can Anyone explain me why OAuth2AccessTokenSupport always returns POST and
How to send HTTP GET request
To enable GET requests for the token endpoint, you need to add the following in your AuthorizationServerConfigurerAdapter:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
As for why only POST by default: I think that is due to GET requests potentially sending username and password information as request params (this is certainly the case for password grant). These may well be visible in web server logs, while POST body data is not.
Indeed the RFC for OAuth2 declares that the client must use HTTP POST when requesting an access token (https://www.rfc-editor.org/rfc/rfc6749#section-3.2)
Related
i have laravel site and i want create android app for this site
and im beginner in java .
In summary...
for authentication api route i use one middleware .
this middleware have one token .
in the postman program all thing is good...
but when i want send one post request with header token in volley android
my function cant give username or some variable ...
please help me to resolve this problem
this is my function send volly , dont forget all thing is good in postman request
int selectedId = statusregister.getCheckedRadioButtonId();
radioselect=(RadioButton)findViewById(selectedId);
send=0;
String url="my http api site...";
requestQueue= Volley.newRequestQueue(RegisterActivity.this);
StringRequest stringRequest=new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("response",response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("HttpClient", "error: " + error.toString());
}
}){
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>(); params.put("username",username.getText().toString().trim());
params.put("email",mailuser.getText().toString().trim());
params.put("password",password.getText().toString().trim());
params.put("status",radioselect.getText().toString().trim());
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params2 = new HashMap<String, String>();
params2.put("Content-Type", "application/json; charset=UTF-8");
params2.put("APP_KEY", "7ACFdsd328BEA81sssdfgg556B91");
return params2;
}
};
requestQueue.add(stringRequest);
}
401 erorr ...
when i remove middleware its ok ...
this is screenshot begore set APP_KEY in header
enter image description here
and this screenshot after set APP_KEY in header
enter image description here
401 is an authorization issue
The default API token name in laravel is access_token not APP_KEY
params2.put("access_token", "7ACFdsd328BEA81sssdfgg556B91");
The API_KEY is an environment variable used for encryption in Laravel and you're sending it as a header in a post request
I have read about controller based exceptions using #ExceptionHandler.
I have read about global exception handling using #ControllerAdvice.
I have also read about extending HandlerExceptionResolver for more in-depth exception handling.
However, what I would ideally like to do is be able to throw a global exception with parameters that dictate a JSON response returned to the client, at any layer in my application.
For instance:
throw new CustomGlobalException(HttpStatus.UNAUTHORISED, "This JWT Token is not Authorised.")
throw new CustomGlobalException(HttpStatus.FORBIDDEN, "This JWT Token is not valid.")
This would then return a JSON response based on the model I've created, along with the status, such as :
{
"success" : "false",
"message" : "This JWT Token is not Authorised."
}
And for this to be returned as a REST response from my controller.
Is something like this possible? Or Do I have to go through the process of making custom error exceptions for everything as described in the documentation.
To clarify, I require the exception to interrupt whatever the ongoing process is, perhaps fetching data from the database, and immediately return the given exception to the client. I have a web mvc setup.
Further details:
#ControllerAdvice
#RequestMapping(produces = "application/json")
public class GlobalExceptionHandler {
#ExceptionHandler(CustomException.class)
public ResponseEntity<Object> handleCustomException(CustomException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getCode());
}
}
Exception thrown here:
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
logger.debug("Filtering request for JWT header verification");
try {
String jwt = getJwtFromRequest(request);
logger.debug("JWT Value: {}", jwt);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken
(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
logger.error("No Valid JWT Token Provided");
throw new CustomException(HttpStatus.UNAUTHORIZED, "No Valid JWT Token Provided");
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
This doesn't exactly do what you want to achieve, but the simplest way of doing almost what you want (and is cleaner, IMO), is to simply define an exception like the following:
#ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException {
public UnauthorisedException(String message) {
super(message);
}
}
Now every time such an exception is thrown (not returned) from a controller method (directly or indirectly), you'll get a response such as
{
"timestamp": "2018-06-24T09:38:51.453+0000",
"status": 401,
"error": "Unauthorized",
"message": "This JWT Token is not Authorised.",
"path": "/api/blabla"
}
And of course the actual status code of the HTTP response will also be 401.
You can also throw a ResponseStatusException, which is more generic and allows you to use the same exception type and pass the status as argument. But I find it less clean.
Following my post on how to handle exception here, you can write your own handler something like this,
class CustomGlobalException {
String message;
HttpStatus status;
}
#ExceptionHandler(CustomGlobalException.class)
public ResponseEntity<Object> handleCustomException(CustomGlobalException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("success", "false");
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getStatus());
}
Code mentioned above will handle CustomGlobalException occurred any layer of code.
Since Spring 5 and Above, a ResponseStatusException (spring framework provided) would be better.
Please refer to spring-response-status-exception
I am trying to get the jwt access tokens for each user of my gsuite domain using the GoogleCredential and JacksonFactory libraries.
Code sample -
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(clientEmail)
.setServiceAccountScopes(scopes)
.setServiceAccountPrivateKeyFromP12File(privateKeyFile)
.setServiceAccountUser(userEmail)
.build();
credential.refreshToken();
String accessToken = credential.getAccessToken();
All fields - clientEmail, scopes, key and userEmail are neither null nor empty
For a few number of users I am not able to get the access token and am getting this error
com.google.api.client.repackaged.com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191) com.google.api.client.util.Preconditions.checkNotNull(Preconditions.java:127) com.google.api.client.json.jackson2.JacksonFactory.createJsonParser(JacksonFactory.java:96) com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:85) com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81) com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:88) com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287) com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307) com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269) com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489) com.hubble.hubbleEngine.policyTypes.OAuth.getJWTAccessToken(OAuth.java:815)
This is happening only the first time, I am trying to get the access tokens. When I try to get the access tokens again for all users, I am able to get the access tokens for the users which were throwing the error the first time.
I debugged a bit and saw that the error gets generated from the following function present in com.google.api.client.auth.oauth2.TokenRequest
public final HttpResponse executeUnparsed() throws IOException {
// must set clientAuthentication as last execute interceptor in case it needs to sign request
HttpRequestFactory requestFactory =
transport.createRequestFactory(new HttpRequestInitializer() {
public void initialize(HttpRequest request) throws IOException {
if (requestInitializer != null) {
requestInitializer.initialize(request);
}
final HttpExecuteInterceptor interceptor = request.getInterceptor();
request.setInterceptor(new HttpExecuteInterceptor() {
public void intercept(HttpRequest request) throws IOException {
if (interceptor != null) {
interceptor.intercept(request);
}
if (clientAuthentication != null) {
clientAuthentication.intercept(request);
}
}
});
}
});
// make request
HttpRequest request =
requestFactory.buildPostRequest(tokenServerUrl, new UrlEncodedContent(this));
request.setParser(new JsonObjectParser(jsonFactory));
request.setThrowExceptionOnExecuteError(false);
HttpResponse response = request.execute();
if (response.isSuccessStatusCode()) {
return response;
}
throw TokenResponseException.from(jsonFactory, response);
}
The request.execute() hits the "https://accounts.google.com/o/oauth2/token" to get the token but it is throwing some error response. Due to this it throws the TokenResponseException mentioned at last. Here, the response.getContent() is null due to which the whole null exception is occuring.
Is there a way to know, which kind of error response is thrown by the call. (>300 or <200)? Or why such a case is happening ?
here is my problem.
I got a first authentication with mail and JWT with Spring boot 1.5.3.
=> works perfectly
Then i made a SSO filter to allow facebook tokens
The thing is, on first authentication it's ok. My server get the Token, then check with fb that says ok then it says ok to my client.
After that if i don't encode my token with my JWT token enhancer, my server says that it is not able to decode it as JSON.
Just that i know, i would normally not have to encode myself as it should be done automatically after my chain filter if i say ok ??
This code works but i've done the jwt myself, is that possible i've missed something ????
public class MyOAuth2ClientAuthenticationProcessingFilter extends OAuth2ClientAuthenticationProcessingFilter {
public MyOAuth2ClientAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
log.info("[attemptAuthentication facebook]");
Authentication result = null;
try {
String token = request.getHeader("oauth_token");
oauth2ClientContext.setAccessToken(new DefaultOAuth2AccessToken(token));
result = super.attemptAuthentication(request, response);
if(result.isAuthenticated()) {
FacebookService facebookService = new BasicFacebookService(token);
User fbUser = facebookService.getUser();
if(fbUser == null) {
throw new IllegalArgumentException(" fb user cannot be null");
}
if(!userService.isLoginExists(fbUser.getId())) {
CreateSocialUserModel model = new CreateSocialUserModel(
token,
DateUtil.getNow(),
"facebook");
userService.createSocialUser(model, fbUser);
}
//--- Create custom JWT token from facebook token
UserInfoTokenServices tokenService = new UserInfoTokenServices(
"https://graph.facebook.com/me",
facebookProperties.getAppId());
OAuth2AccessToken enhancedToken = jwtTokenEnhancer.enhance(oauth2ClientContext.getAccessToken(),
tokenService.loadAuthentication(oauth2ClientContext.getAccessToken().getValue()));
TokenResponse tokenResponse = new TokenResponse(enhancedToken.getValue(),
enhancedToken.getTokenType(),
enhancedToken.getRefreshToken() != null ? enhancedToken.getRefreshToken().getValue() : "");
ObjectMapper mapper = new ObjectMapper();
String jsonTokenEnhancedJack = mapper.writeValueAsString(tokenResponse);
response.addHeader("Content-Type", "application/json");
response.getWriter().flush();
response.getWriter().print(jsonTokenEnhancedJack);
}
return result;
} catch (Exception e) {
log.info("error");
log.error("error", e);
e.printStackTrace();
} finally {
return result;
}
}
}
Thank you in advance
As asked by Son Goku just putting some code to help him
First you have to put the filter like this
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().permitAll()
.and().csrf().disable();
}
private Filter ssoFilter() {
OAuth2ClientAuthenticationProcessingFilter facebookFilter = new MyOAuth2ClientAuthenticationProcessingFilter("/user/social");
OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(Oauth2facebook(), oauth2ClientContext);
facebookFilter.setRestTemplate(facebookTemplate);
facebookFilter.setTokenServices(new UserInfoTokenServices(
"https://graph.facebook.com/me",
facebookProperties.getAppId()
));
return facebookFilter;
}
After that you can use the OAuth2ClientAuthenticationProcessingFilter as in first question.
Also, in first question i customized this method a lot, it works but i was surprised to not find this as easy as these library use to be.
Hope it helps you, i have struggled a bit too on this.
Maybe now, spring boot handle this much more easily.
I am currently working on spring application and REST webservices.
I have created a REST webservice in one application and want to access that service from other applications.
Below is the error its showing when trying to access the webservice.
RestClientException : org.springframework.web.client.HttpClientErrorException: 401 Full authentication is required to access this resource
Below is my webservice code:
#RequestMapping(value = MyRequestMapping.GET_ACC_DATA, method = RequestMethod.GET)
#ResponseBody
public MyResponseDTO getSigDataValues(#PathVariable final String acc, final HttpServletResponse response) throws Exception {
MyResponseDTO responseDTO = null;
try {
//logic goes here
//responseDTO = ..
} catch (Exception e) {
LOG.error("Exception" + e);
}
return responseDTO;
}
I am calling above webservice from another application.In the below mentioned method I am calling the webservice and its throwing me the exception org.springframework.web.client.HttpClientErrorException.
public MyResponseDTO getAccData(String acc){
try{
list= (List<String>)restTemplate.postForObject(MyDataURL.GET_ACC_DATA.value(), MyResponseDTO.class, acc);
}
catch (final RestClientException e)
{
LOG.info("RestClientException :" + e);
}
Please suggest, what am I missing.
You would need to authenticate against the REST service. One of the most common ways is Basic Authentication. If this is what the service is using you would need to create an AUTHORIZATION header with Base 64 encoded usernamen + password.
RestTemplate allow to set customer headers before the request gets sent.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
private HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {
private static final long serialVersionUID = -1704024310885506847L;
{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}
};
}
Then, sending a request becomes just as simple:
ResponseEntity<Dados> response = restTemplate.exchange(uriComponents.toUriString(), HttpMethod.GET,
new HttpEntity<Dados>(createHeaders(usuario, senha)), Dados.class);