Java Spring Boot Security authorization - java

I'm trying to get a value from my rest api but for some reason it not letting me get it from an authorize user but when i set it permitAll() it does. I'm receiving a 403 error code.
Backend
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers(HttpMethod.GET,"/token/refresh/**").hasAnyAuthority("ROLE_USER");
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/user/**").hasAnyAuthority("ROLE_USER");
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/user/{username}/**").hasAnyAuthority("[ROLE_ADMIN]");
http.authorizeRequests().antMatchers(HttpMethod.POST,"/api/user/save/**").hasAnyAuthority("ROLE_ADMIN");
http.authorizeRequests().antMatchers("/api/login/**","/api/user/save/**","/api/role/addtouser/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.addFilter(customAuthenticationFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
http.httpBasic();
Front-End
here is the request is being send.
getUserId(username) {
this.http.get(`http://localhost:8080/api/user/${username}`).subscribe(
resp=>{
sessionStorage.setItem("id",resp.toString())
}
)
}
Interceptor
this is my interceptor i think it's adding it to the header
export class HttpInterceptorInterceptor implements HttpInterceptor {
constructor(private authrnticationService: AuthenticationServiceService, private router:Router) {}
intercept(req: HttpRequest<any>, next: HttpHandler){
let httpHeaders = new HttpHeaders();
let basicAuthHeaderString=this.authrnticationService.getAuthenticatedtoken();
let username= this.authrnticationService.getEmail();
if (!req.headers.has('Content-Type')) {
httpHeaders = httpHeaders.append('Content-Type', 'application/x-www-form-urlencoded')
}
if (basicAuthHeaderString) {
httpHeaders = httpHeaders.append('Authorization', basicAuthHeaderString)
}
const xhr=req.clone({
headers: httpHeaders
})
return next.handle(xhr).pipe(tap(() => {},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status !== 401) {
return;
}
sessionStorage.clear()
this.router.navigate(['login']);
}
}));
}
}

Related

Not able to read cookies in Angular from API response (Spring Boot Service) - Cannot read properties of null (reading 'headers')

Service Code
public ResponseEntity<String> getSessionCookie() {
logger.info("Get Cookies");
var cookie1 = ResponseCookie.from("ASP.NET_SessionId_Wx", appConfig.getSessionId()).httpOnly(false).path("/").secure(false).build();
var cookie2 = ResponseCookie.from("WX-XSRF-TOKEN", appConfig.getToken()).httpOnly(false).path("/").build();
return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie1.toString())
.header(HttpHeaders.SET_COOKIE, cookie2.toString()).build();
}
Angular Code
Service
public getSession(): Observable<any> {
return this.http.get<any>('//example.com/getSessionCookie/', {withCredentials: true});
}
Component
this.ds.getSession().subscribe((res) => {
console.log('Get Session Header: ', res.headers);
})
}
Able to view the cookies in Postman and Chrome Dev Tools (Network tab - Response Headers)
Added CORS config to SprinBoot App
public class CorsConfiguration implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOriginPatterns("*").allowedHeaders("*").allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
}
I figured it out.
The issue was with the 'Set-Cookie'.
Angular is unable to read the 'Set-Cookie' header. Changed the header key to some other name and added the same in exposedHeaders as well.
Worked like a Charm:).
Thanks.

Forward client error from auth service to the client during gateway filter

I create an API-Gateway which should validate
the provided token of request via authservice. If unauthorized exception arrived it should be forwarded to client. It looks like:
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
if (!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
return this.onError(exchange, "Authorization header is missing in request", HttpStatus.UNAUTHORIZED);
}
String authHeader = Objects.requireNonNull(exchange
.getRequest()
.getHeaders()
.get(org.springframework.http.HttpHeaders.AUTHORIZATION)).get(0);
String[] parts = authHeader.split(" ");
if (parts.length != 2 || !"Bearer".equals(parts[0])) {
return this.onError(exchange, "Authorization header is invalid", HttpStatus.UNAUTHORIZED);
}
String token = parts[1];
return webclientBuilder
.build()
.post()
.uri("http://AUTH-SERVICE/auth/users/validateToken?token=" + token)
.retrieve()
.bodyToMono(UserModel.class)
.map(userModel -> {
exchange.getRequest()
.mutate()
.header("x-auth-user-id", String.valueOf(userModel.getId()))
.header("x-auth-user-role", String.valueOf(userModel.getRole()));
return exchange;
}).flatMap(chain::filter);
};
}
My API-Gateway service getting unauthorized exception from authservice but it throws 500er and client get the 500er.
My assumption is the unauthorized exception is not handled, but tried to handle like:
return webclientBuilder
...
.retrieve()
.onStatus(HttpStatus::is4xxClientError, ClientResponse::createException)
.bodyToMono(UserModel.class)
...;
but still throw 500 error to the client. How can I forward the client error from auth service to the client during gateway filter? Can anyone help me with that please?

Kotlin Spring security + JWT - 401 on registration endpoint

I am working on application to learn something more about jwt authentication and I have problem with registration.
I put signup url in antMatchers to permittAll but it does not work. Here is the code:
const val AUTH_LOGIN_URL = "/library/authenticate"
const val SIGN_UP_URL = "/library/signup"
Security Config :
override fun configure(http: HttpSecurity?) {
http?.cors()?.and()
?.csrf()?.disable()
?.authorizeRequests()
?.antMatchers(SIGN_UP_URL, AUTH_LOGIN_URL)?.permitAll()
?.anyRequest()?.authenticated()
?.and()
?.exceptionHandling()?.authenticationEntryPoint(authenticationEntryPoint)
?.and()
?.sessionManagement()
?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http?.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter::class.java)
}
Jwt filter:
#Component
class JwtRequestFilter(
#Autowired
val jwtTokenProvider: JwtTokenProvider,
#Autowired
val customUserDetailsService: CustomUserDetailsService
) : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
var username: String
var jwtToken = getJwtFromRequrst(request)
try {
if (!StringUtils.isEmpty(jwtToken)) {
username = jwtTokenProvider.getUsernameFromToken(jwtToken)
val userDetails = customUserDetailsService.loadUserByUsername(username)
val authentication = UsernamePasswordAuthenticationToken(userDetails, null, emptyList())
authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
SecurityContextHolder.getContext().authentication = authentication
}
} catch (e: Exception) {
logger.error("Could not set user authentication in security context", e)
}
filterChain.doFilter(request, response)
}
private fun getJwtFromRequrst(request: HttpServletRequest): String {
val bearerToken = request.getHeader(TOKEN_HEADER)
if (!StringUtils.isEmpty(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7, bearerToken.length)
}
return ""
}
}
Entry point:
#Component
class WebSecurityEntryPoint: AuthenticationEntryPoint {
override fun commence(request: HttpServletRequest?, response: HttpServletResponse?, authException: AuthenticationException?) {
response?.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access denied")
}
}
Using SIGN_UP_URL I always receive 401. Could you help me?
Ok I resolve issue:
I changed the Controller by adding request mapping:
#RestController
#RequestMapping("/auth")
class AuthenticationController
and then in security config:
?.antMatchers("/auth/**")?.permitAll()
It starts working.
I think this was the problem:
?.antMatchers(SIGN_UP_URL, AUTH_LOGIN_URL)?.permitAll()
Maybe if I will declare it one by one it would also work

Can not get token (OAUTH2, Spring, Kotlin)

I try to get token but it not works. Request work in postman, but when I try reproduce this in angular I getting:
My request in postman:
My request in angular:
getToken() {
const headers = new HttpHeaders();
headers.set('Authorization', 'Basic ZGV2Z2xhbi1jbGllbnQ6ZGV2Z2xhbi1zZWNyZXQ=');
headers.set('Content-Type', 'application/x-www-form-urlencoded');
const body = new URLSearchParams();
body.append('username', 'Alex123');
body.append('password', 'password');
body.append('grant_type', 'password');
this.http.post<AuthToken>('http://localhost:8080/oauth/token', body, {headers: headers})
.subscribe(
success => {
debugger
this.token = success.access_token;
}
);
}
my CORS configure, i thing all is good with it.:
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/api-docs/**").permitAll()
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/auth/token").permitAll()
}
#Bean
fun corsFilter(): FilterRegistrationBean<*> {
val source = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration()
config.allowCredentials = java.lang.Boolean.TRUE
config.addAllowedOrigin("*")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
source.registerCorsConfiguration("/**", config)
val bean = FilterRegistrationBean(CorsFilter(source))
bean.order = 0
return bean
}
It seems you have issues with CORS, please read the following article about to learn more about CORS.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
This answer should be an comment, but I'm unable to comment..

Swagger UI Basic Authentication doesn't work, but curl does

I have a rest API implemented in Java (MSF4J codegen from swagger) and a swagger 2 definition that describes it.
A swagger UI is hosted on a web server. The API is deployed on a VM somewhere on the internet.
My Problem is that the "try it out" function of the swagger UI doesn't work. I always get a "401 Unauthorized". When I take the curl command from the UI and paste it into my terminal it works.
Last week I didn't have HTTPS or Basic Authentication - just HTTP - and it worked fine. Now I don't know why it doesn't work.
Since I changed the swagger definition to https the UI makes an OPTIONS request. I implemented that, but I get 401 responses.
The certificate comes from Lets Encrypt and is used by an apache web server. The apache is a proxy to the rest api on the same machine.
Here is my authentication interceptor:
public class BasicAuthSecurityInterceptor extends AbstractBasicAuthSecurityInterceptor {
#Override
protected boolean authenticate(String username, String password) {
if (checkCredentials(username, password))
return true;
return false;
}
private boolean checkCredentials(String username, String password) {
if (username.equals("testuser"))
return BCrypt.checkpw(password, "$2a$10$iXRsLgkJg3ZZGy4utrdNyunHcamiL2RmrKHKyJAoV4kHVGhFv.d6G");
return false;
}
}
Here is a part of the api:
public abstract class DeviceApiService {
private static final Logger LOGGER = LogManager.getLogger();
public abstract Response deviceGet() throws NotFoundException;
public abstract Response deviceIdAvailableLoadGet(Integer id, Long from, Long to, String resolution)
throws NotFoundException;
public abstract Response deviceIdGet(Integer id) throws NotFoundException;
protected Response getOptionsResponse() {
String allowedOrigin = "";
try {
allowedOrigin = PropertyFileHandler.getInstance().getPropertyValueFromKey("api.cors.allowed");
} catch (IllegalArgumentException | PropertyException | IOException e) {
LOGGER.error("Could not get allowed origin.", e);
}
Response response = Response.ok().header("Allow", "GET").header("Access-Control-Allow-Origin", allowedOrigin)
.header("Access-Control-Allow-Headers", "authorization, content-type").build();
return response;
}
}
public class DeviceApi {
private final DeviceApiService delegate = DeviceApiServiceFactory.getDeviceApi();
// #formatter:off
#GET
#Produces({ "application/json" })
#io.swagger.annotations.ApiOperation(
value = "Get devices",
notes = "",
response = Device.class,
responseContainer = "List",
authorizations = { #io.swagger.annotations.Authorization(value = "basicAuth") },
tags = { "Device", }
)
#io.swagger.annotations.ApiResponses(
value = { #io.swagger.annotations.ApiResponse(
code = 200,
message = "200 OK",
response = Device.class,
responseContainer = "List")
})
public Response deviceGet() throws NotFoundException {
return delegate.deviceGet();
}
#OPTIONS
#Consumes({ "application/json" })
#Produces({ "application/json" })
#io.swagger.annotations.ApiOperation(value = "CORS support", notes = "", response = Void.class, authorizations = {
#io.swagger.annotations.Authorization(value = "basicAuth") }, tags = { "Device", })
#io.swagger.annotations.ApiResponses(value = {
#io.swagger.annotations.ApiResponse(code = 200, message = "Default response for CORS method", response = Void.class) })
public Response deviceOptions() throws NotFoundException {
return delegate.getOptionsResponse();
}
}
EDIT:
This are the headers of the request the swagger ui creates:
Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: de,en-US;q=0.7,en;q=0.3
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
DNT: 1
Host: api.myfancyurl.com
Origin: http://apidoc.myfancyurl.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0
It seems that the authorization header is missing. When I edit the request and resend it with the authorization header and encoded credentials it works.
But I don't know why swagger doesn't add this header. Should one accept all options requests without authorization?

Categories

Resources