how to send refreshToken to the token endpoint? - java

I am using JWT Tokens with springboot-security-jwt, that have some documentation about token generation, but none about how to send the refreshToken to the token endpoint: using POST? GET? packing parameters in JSON? there are an example of the JSON pack?
NOTES
My endpoint can be used as localhost, https://localhost:8080/api/user/register, and it is working fine... return a JSON like this,
{
"refreshToken": "eyJhbGciOiJIUzUxMiJ9......Jj3hnQuMd6Im9AJhmmxaA7ILiERqHuTUf0BYCerWe4ziggvs2PiCfB_3J2f_Gc3hOqY1IgJWJRm_LrTs1UcxwQ",
"token": "eyJhbGciOiJIUzUxMiJ9......-CWgg4srJoevN7PVKOQfsQXAE3h5ySkabUb-Q-xPsEQO18KSYXWw"
}
but, how to send refreshToken to api/auth/token endpoint?
(I not see any clues at your article)
Using postman with a POST to https://localhost:8080/api/auth/token with body
{"refreshToken": "eyJhbGciOiJIUzUxMiJ9.......Jj3hnQuMd6Im9AJhmmxaA7ILiERqHuTUf0BYCerWe4ziggvs2PiCfB_3J2f_Gc3hOqY1IgJWJRm_LrTs1UcxwQ",
}
I have response
{
"errorCode": 10,
"message": "Authentication failed",
"status": 401,
"timestamp": 1481753363749
}
Perhaps other problem...
(edit with more clues about my implementation)
My configs at my equivalent WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final String JWT_TOKEN_HEADER_PARAM = "Authorization";
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/login";
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/auth/**";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/token";
...
}
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // We don't need CSRF for JWT based authentication
.exceptionHandling()
.authenticationEntryPoint(this.authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
.and()
.authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
.and()
.addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
}
so, perhaps (?) no endpoint /token exist (!) with this changes.
... Where the springboot-security-jwt /token implementation? to check it (or a kind of "health endpoint test")...
PS: the spected endpoint "/api/token" and any other "api/Mammy" returns 405 (Method Not Allowed), and testing as authorized endpoint, "auth/token" or "api/Mammy", returns 401 and error 10 (Authentication failed).

Related

401 error when im going to do a get request in postman

Similar to 403 Forbidden, but specifically for use when authentication
is possible but has failed or not yet been provided. The response must
include a WWW-Authenticate header field containing a challenge
applicable to the requested resource.
#RestController()
#RequestMapping("/rest")
public class PaisRestController {
IPaisService paisService;
#GetMapping("/example")
public String home(#RequestAttribute("Username") String username) {
return "Hello, " + username + "!";
}
#GetMapping("/findById/{pais_id}")
public Pais getPaisById(#PathVariable("pais_id") Long pais_id) {
System.out.println(paisService.getPaisPorId(pais_id));
return paisService.getPaisPorId(pais_id);
}
}
}
I don't know how to fix this problem, when I send the request in postman, I get this error. I have my Bearer Token in my headers values and authorizations in keys.
The URL I'm using:
http://localhost:8080/CashLetterAPI/rest/findById/1
Project structure
UPDATE 2:
My configure method:
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/rest/**")
.authorizeRequests()
.anyRequest().permitAll()
.and()
.addFilterBefore(customJWTAuthFilter, BasicAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(unauthorizedRestEntryPoint)
.and()
.csrf().disable();
}
}

Why /logout calling throws "Method not allowed"?

My app using Spring Session (with Redis). And i use custom login controller, because i use external React client, not default Spring login page.
Login controller:
#PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_VALUE)
public String login(#RequestBody LoginDataTo loginData) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
loginData.getEmail(),
loginData.getPassword());
Authentication authentication = this.authenticationManager.authenticate(token);
SecurityContextHolder
.getContext()
.setAuthentication(authentication);
return "OK";
}
Security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
http
.httpBasic().disable()
.formLogin().disable() // login form is disable, because i use external React client
.csrf().disable()
.cors().disable();
http
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true);
http
.authorizeRequests()
.antMatchers("/login").anonymous()
.antMatchers("/logout").authenticated()
.anyRequest().authenticated();
}
So... The /login endpoint's work is correct. But /logout endpoint work is incorrect. When calling /logout, it returns json:
{
"timestamp": "2021-03-30T13:45:09.142+00:00",
"status": 405,
"error": "Method Not Allowed",
"message": "",
"path": "/login"
}
Here is the request, which i using in Postman:
GET http://localhost:8080/logout
Cookie and session are deleted, that is logout's work is correct, but why is it returning this json?
I solved the problem by means of logoutSuccessHandler setting:
http
.logout()
.invalidateHttpSession(true)
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
Now /logout calling returns 200 OK.

OAuth2 with Google - CORS Error (Angular + Spring boot) [duplicate]

This question already has an answer here:
CORS issue while making an Ajax request for oauth2 access token
(1 answer)
Closed 3 years ago.
I have problem with CORS error. I do request for Google oAuth2 and i get a CORS ERROR:
I want to get google authentication and generate a JWT token. When I do it without using the client everything is fine. When I send angular requests this is a problem with CORS. I allow all types of CORS. Why am I getting this error?
Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=1020159669873-d9r35ssmnejud852bam87d8gqtcj5qf1.apps.googleusercontent.com&scope=openid%20profile%20email&state=8nizHP1X2z9sA8m0vqM4Lzd6VT24R15eSw5flteTywM%3D&redirect_uri=http://localhost:8080/oauth2/callback/google' (redirected from 'http://localhost:8080/oauth2/authorization/google')
from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=1020159669873-d9r35ssmnejud852bam87d8gqtcj5qf1.apps.googleusercontent.com&scope=openid%20profile%20email&state=8nizHP1X2z9sA8m0vqM4Lzd6VT24R15eSw5flteTywM%3D&redirect_uri=http://localhost:8080/oauth2/callback/google with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.
My Angular request:
googleLogin(): Observable<LoginResponse> {
return this.http.get<LoginResponse>
(environment.baseUrl + '/oauth2/authorization/google')
.pipe(tap(response => {
localStorage.setItem('access_token', response.accessToken);
}));
}
//...
public onGoogleLogin(): void {
this.authService.googleLogin().subscribe();
}
//...
CORS CONFIG:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
.maxAge(MAX_AGE_SECS);
}
Security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/v1/oauth0/**")
.permitAll()
.antMatchers("/api/v1/oauth2/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
// włączenie obslugi oauth2
.oauth2Login()
.successHandler(this.successHandler)
.redirectionEndpoint()
.baseUri("/oauth2/callback/*")
.and()
.userInfoEndpoint()
.oidcUserService(customOidcUserService);
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
Success Handler:
#Autowired
private UserRepository userRepository;
#Autowired
private JwtTokenProvider tokenProvider;
private final static String URL = "http://localhost:8080/api/v1/oauth2/authenticate";
#Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
if (response.isCommitted()) {
return; }
DefaultOidcUser oidcUser = (DefaultOidcUser) authentication.getPrincipal();
System.out.println(oidcUser);
Map attributes = oidcUser.getAttributes();
String email = attributes.get("email").toString();
User user = userRepository.findByEmail(email).orElseThrow(
() -> new ResourceNotFoundException("User", "email", email)
);
String token = tokenProvider.generateToken(user);
String redirectionUrl = UriComponentsBuilder.fromUriString(URL).queryParam("token", token)
.build().toUriString();
getRedirectStrategy().sendRedirect(request, response, redirectionUrl);
}
}
Controller:
#RestController
#RequestMapping("/api/v1/oauth2")
public class OAuth2Controller {
#GetMapping("/authenticate")
public ResponseEntity<?> authenticateUser(#RequestParam String token) {
return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}
}
You cannot get the token in this example as you need to make actual redirects. There are couple of ways you could circumvent this requirement which is detailed in RFC https://www.rfc-editor.org/rfc/rfc6749#section-1.2
Initiate authorization flow in a popup and pass back the token received by server via postMessage() API provided in the browser, from the popup window back to the webapp.
Save the state, whatever it is, redirect to server which will initiate authorization flow and after token is exchanged for a grant, redirect back to the webapp with a token as a query string parameter. Then use it and restore the state.

How to call rest endpoint via Spring restTemplate that is protected by Keycloak

Preconditions
I have two Java Spring applications(App 'A' and App 'B') that were created via JHipster(monolithic application). Both applications uses keycloak for authentication/authorization.
Both applications have an angular frontend and support login via ouath (spring-security). Here ist my SecurityConfiguration of Application A and B:
#Configuration
#Import(SecurityProblemSupport.class)
#EnableOAuth2Sso
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
#Bean
public AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler() {
return new AjaxLogoutSuccessHandler();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**")
.antMatchers("/h2-console/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.addFilterBefore(corsFilter, CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler())
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/profile-info").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN);
}
}
In App B i also have an ResourceServerConfiguration. This checks if the header contains an "Authorization" key. If true, the user can login via JWT(Bearer Authentication). I tested this via Postman and it works fine:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.requestMatcher(new RequestHeaderRequestMatcher("Authorization")).authorizeRequests()
.anyRequest().authenticated();
}
}
Further more both apps are in the same keycloak realm and have the access-type "public".
Problem:
Now i want to call an endpoint of App B via an Spring RestTemplate from App A. The problem is, that i do not have an access_token that i can put in my rest request/restTemplate. When i look in my request that is send from my frontend, i only got an JSESSIONID. There is no access_token/JWT in the header.
Question
Is there a way to get the access_token of the current user out of the JSESSIONID/the HttpSession or the spring security context? Do i need something like a Tokenstore where i store every token that comes from keycloak?
Did anyone else have similar problems or any idea how i could solve that problem?
After some research it turns out that the problem lies within the generated jhipster code.
I followed the authentication process in the application and saw, that there was a call to the /account endpoint directly after authentication, where the user information were retrieved. The call is triggerd by the frontend. First time this endpoint is called, there is a principal with a bearer token available. Within the /account endpoint, a call to the userService with the principal object is performed. More precisley
getUserFromAuthentication(OAuth2Authentication authentication)
is called. Within this method there is a part that replaces the OAuth2Authentication with a new UsernamePasswordAuthenticationToken and inserts it into the SecurityContext:
UsernamePasswordAuthenticationToken token = getToken(details, user,
grantedAuthorities);
authentication = new OAuth2Authentication(authentication.getOAuth2Request(), token);
SecurityContextHolder.getContext().setAuthentication(authentication);
So after that, the access_token is lost. I am not quite sure, why it was replaced with the new OAuth2Authentication, but i tend to extend this part and keep the access_token in my securityContext for further restcalls.

how to achieve Ldap Authentication using spring security(spring boot)

I have following code with me
I am trying to achieve ldap Authentication but i think it is not happening.
My Security Configuration
#EnableWebSecurity
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class Config extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/*")
.permitAll().anyRequest().authenticated().and().csrf()
.disable().httpBasic().and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.ldapAuthentication()
.userSearchFilter("(uid={0})")
.userSearchBase("dc=intern,dc=xyz,dc=com")
.contextSource()
.url("ldap://192.168.11.11:1234/dc=intern,dc=xyz,dc=com")
.managerDn("username")
.managerPassword("password!")
.and()
.groupSearchFilter("(&(objectClass=user)(sAMAccountName=" + "username" + "))");
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request
.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
response.sendRedirect("/notAllowed");
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
My Controller
#RequestMapping(value = { "/test" }, method = RequestMethod.GET)
public #ResponseBody String retrieve() {
System.out.println("line 1");
System.out.println("line 2");
return "hello";
}
#RequestMapping(value = { "/notAllowed" }, method = RequestMethod.GET)
public #ResponseBody HttpStatus login() {
return HttpStatus.FORBIDDEN;
}
i am aiming for :
i want to achieve ldap authentication. Username and password will come from browser though i have tried with hardcoded username and password as well.
if user is authentic then filter will check the authorizátion by checking the token .
if this is first request then new token will be generated and sent.
if its not found then it will send the HTTP Status forbidden.
I have following problems :
when i run first time from browser it returns forbidden but it also prints "line 1 and line 2" in console though it do not return hello but forbidden.
are my htpSecurity and ldap Configuration fine?.
from 2nd request it always return hello , i have tried to open new tab ,new request but still it works fine .If i restart server then only it generates token and compare it with cookies token.what if two people are using same system (different times).
how exactly i can test ldap authentication ? i am using POSTMAN as a client .
If some information is missing from my end please let me know .
And i will be thankful for your answers.
First of all, I think your HttpSecurity config is wrong. You want to protect ALL the endpoints. Don't you?
So change it to the following:
http.httpBasic()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
Furthermore, I'm not sure whether your ldap config is right. I think you can reduce it to the following:
auth.ldapAuthentication()
.userSearchFilter("uid={0}")
.contextSource()
.url("ldap://192.168.11.11:1234/dc=intern,dc=xyz,dc=com");
Make sure if your userSearchBase is right. It doesn't have an "ou".
If you don't have any different organizational units, you can simply remove the userSearchBase
To provide better help i need to know the structure of your ldap.
If you want to check your HttpSecurity config you may not use ldap in the first place and use inMemoryAuthentication instead:
auth.inMemoryAuthentication().withUser("user").password("password").authorities("ROLE_USER");

Categories

Resources