FINERACT-1012: Upgrading OAuth support to Spring Security 5.6
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
b6a9a2791d
commit
c74bfed1fe
-44
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.boot;
|
||||
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* This Configuration replaces what formerly was in web.xml. Beans are loaded only when "oauth" Profile is enabled.
|
||||
*
|
||||
* @see <a href=
|
||||
* "http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-convert-an-existing-application-to-spring-boot">#howto-convert-an-existing-application-to-spring-boot</a>
|
||||
*/
|
||||
@Configuration
|
||||
@Profile("oauth")
|
||||
public class WebXmlOauthConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
|
||||
ServletRegistrationBean<DispatcherServlet> registrationBean = new ServletRegistrationBean<DispatcherServlet>(dispatcherServlet);
|
||||
registrationBean.addUrlMappings("/api/oauth/token");
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.fineract.infrastructure.core.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.exceptionmapper.OAuth2ExceptionEntryPoint;
|
||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareTenantIdentifierFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
|
||||
import org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.access.vote.UnanimousBased;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
|
||||
@Configuration
|
||||
@Profile("oauth")
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private TenantAwareTenantIdentifierFilter tenantAwareTenantIdentifierFilter;
|
||||
|
||||
@Autowired
|
||||
private TenantAwareJpaPlatformUserDetailsService userDetailsService;
|
||||
|
||||
private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http //
|
||||
.csrf().disable() // NOSONAR only creating a service that is used by non-browser clients
|
||||
.antMatcher("/api/**").authorizeRequests() //
|
||||
.antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/echo").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/authentication").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/self/authentication").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/self/registration").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/self/registration/user").permitAll() //
|
||||
.antMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
|
||||
.antMatchers("/api/*/twofactor").fullyAuthenticated() //
|
||||
.antMatchers("/api/**").access("isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')") //
|
||||
.accessDecisionManager(accessDecisionManager()).and() //
|
||||
.exceptionHandling().authenticationEntryPoint(new OAuth2ExceptionEntryPoint()).and()
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
|
||||
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
|
||||
.sessionManagement() //
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
|
||||
.and() //
|
||||
.addFilterAfter(tenantAwareTenantIdentifierFilter, SecurityContextPersistenceFilter.class) //
|
||||
.addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
|
||||
.requiresChannel(channel -> channel.antMatchers("/api/**").requiresSecure());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
private Converter<Jwt, FineractJwtAuthenticationToken> authenticationConverter() {
|
||||
return jwt -> {
|
||||
try {
|
||||
UserDetails user = userDetailsService.loadUserByUsername(jwt.getSubject());
|
||||
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");
|
||||
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
|
||||
return new FineractJwtAuthenticationToken(jwt, authorities, user);
|
||||
} catch (UsernameNotFoundException ex) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN), ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessDecisionManager accessDecisionManager() {
|
||||
List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(new RoleVoter(), new AuthenticatedVoter(),
|
||||
new WebExpressionVoter(), new SelfServiceUserAccessVote());
|
||||
|
||||
return new UnanimousBased(decisionVoters);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TenantAwareTenantIdentifierFilter> tenantAwareTenantIdentifierFilterRegistration() throws Exception {
|
||||
FilterRegistrationBean<TenantAwareTenantIdentifierFilter> registration = new FilterRegistrationBean<TenantAwareTenantIdentifierFilter>(
|
||||
tenantAwareTenantIdentifierFilter);
|
||||
registration.setEnabled(false);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TwoFactorAuthenticationFilter> twoFactorAuthenticationFilterRegistration() {
|
||||
FilterRegistrationBean<TwoFactorAuthenticationFilter> registration = new FilterRegistrationBean<TwoFactorAuthenticationFilter>(
|
||||
twoFactorAuthenticationFilter);
|
||||
registration.setEnabled(false);
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.exceptionmapper;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
public class OAuth2ExceptionEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
|
||||
throws IOException, ServletException {
|
||||
|
||||
ApiGlobalErrorResponse errorResponse = ApiGlobalErrorResponse.unAuthenticated();
|
||||
response.setContentType("application/json");
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.writeValue(response.getOutputStream(), errorResponse);
|
||||
} catch (Exception e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
-50
@@ -19,7 +19,6 @@
|
||||
package org.apache.fineract.infrastructure.security.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@@ -31,24 +30,23 @@ import java.util.Set;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.security.constants.TwoFactorConstants;
|
||||
import org.apache.fineract.infrastructure.security.data.AuthenticatedOauthUserData;
|
||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||
import org.apache.fineract.infrastructure.security.service.SpringSecurityPlatformSecurityContext;
|
||||
import org.apache.fineract.infrastructure.security.service.TwoFactorUtils;
|
||||
import org.apache.fineract.useradministration.data.RoleData;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.useradministration.domain.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/*
|
||||
@@ -60,19 +58,15 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("singleton")
|
||||
|
||||
@Tag(name = "Fetch authenticated user details", description = "")
|
||||
@SuppressWarnings("deprecation") // TODO FINERACT-1012
|
||||
public class UserDetailsApiResource {
|
||||
|
||||
private final ResourceServerTokenServices tokenServices;
|
||||
private final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService;
|
||||
private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext;
|
||||
private final TwoFactorUtils twoFactorUtils;
|
||||
|
||||
@Autowired
|
||||
public UserDetailsApiResource(@Qualifier("tokenServices") final ResourceServerTokenServices tokenServices,
|
||||
final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService,
|
||||
public UserDetailsApiResource(final ToApiJsonSerializer<AuthenticatedOauthUserData> apiJsonSerializerService,
|
||||
final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext, final TwoFactorUtils twoFactorUtils) {
|
||||
this.tokenServices = tokenServices;
|
||||
this.apiJsonSerializerService = apiJsonSerializerService;
|
||||
this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext;
|
||||
this.twoFactorUtils = twoFactorUtils;
|
||||
@@ -83,48 +77,57 @@ public class UserDetailsApiResource {
|
||||
@Operation(summary = "Fetch authenticated user details\n", description = "checks the Authentication and returns the set roles and permissions allowed.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = UserDetailsApiResourceSwagger.GetUserDetailsResponse.class))) })
|
||||
public String fetchAuthenticatedUserData(
|
||||
@QueryParam("access_token") @Parameter(description = "access_token") final String accessToken) {
|
||||
public String fetchAuthenticatedUserData() {
|
||||
|
||||
final Authentication authentication = this.tokenServices.loadAuthentication(accessToken);
|
||||
if (authentication.isAuthenticated()) {
|
||||
final AppUser principal = (AppUser) authentication.getPrincipal();
|
||||
|
||||
final Collection<String> permissions = new ArrayList<>();
|
||||
AuthenticatedOauthUserData authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), permissions);
|
||||
|
||||
final Collection<GrantedAuthority> authorities = new ArrayList<>(authentication.getAuthorities());
|
||||
for (final GrantedAuthority grantedAuthority : authorities) {
|
||||
permissions.add(grantedAuthority.getAuthority());
|
||||
}
|
||||
|
||||
final Collection<RoleData> roles = new ArrayList<>();
|
||||
final Set<Role> userRoles = principal.getRoles();
|
||||
for (final Role role : userRoles) {
|
||||
roles.add(role.toData());
|
||||
}
|
||||
|
||||
final Long officeId = principal.getOffice().getId();
|
||||
final String officeName = principal.getOffice().getName();
|
||||
|
||||
final Long staffId = principal.getStaffId();
|
||||
final String staffDisplayName = principal.getStaffDisplayName();
|
||||
|
||||
final EnumOptionData organisationalRole = principal.organisationalRoleData();
|
||||
|
||||
final boolean requireTwoFactorAuth = twoFactorUtils.isTwoFactorAuthEnabled()
|
||||
&& !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION);
|
||||
if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) {
|
||||
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), principal.getId(), accessToken,
|
||||
requireTwoFactorAuth);
|
||||
} else {
|
||||
|
||||
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), officeId, officeName, staffId,
|
||||
staffDisplayName, organisationalRole, roles, permissions, principal.getId(), accessToken, requireTwoFactorAuth);
|
||||
}
|
||||
return this.apiJsonSerializerService.serialize(authenticatedUserData);
|
||||
final SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
final FineractJwtAuthenticationToken authentication = (FineractJwtAuthenticationToken) context.getAuthentication();
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final AppUser principal = (AppUser) authentication.getPrincipal();
|
||||
if (principal == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Collection<String> permissions = new ArrayList<>();
|
||||
AuthenticatedOauthUserData authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), permissions);
|
||||
|
||||
final Collection<GrantedAuthority> authorities = new ArrayList<>(authentication.getAuthorities());
|
||||
for (final GrantedAuthority grantedAuthority : authorities) {
|
||||
permissions.add(grantedAuthority.getAuthority());
|
||||
}
|
||||
|
||||
final Collection<RoleData> roles = new ArrayList<>();
|
||||
final Set<Role> userRoles = principal.getRoles();
|
||||
for (final Role role : userRoles) {
|
||||
roles.add(role.toData());
|
||||
}
|
||||
|
||||
final Long officeId = principal.getOffice().getId();
|
||||
final String officeName = principal.getOffice().getName();
|
||||
|
||||
final Long staffId = principal.getStaffId();
|
||||
final String staffDisplayName = principal.getStaffDisplayName();
|
||||
|
||||
final EnumOptionData organisationalRole = principal.organisationalRoleData();
|
||||
|
||||
final boolean requireTwoFactorAuth = twoFactorUtils.isTwoFactorAuthEnabled()
|
||||
&& !principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION);
|
||||
|
||||
if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) {
|
||||
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), principal.getId(),
|
||||
authentication.getToken().getTokenValue(), requireTwoFactorAuth);
|
||||
} else {
|
||||
authenticatedUserData = new AuthenticatedOauthUserData(principal.getUsername(), officeId, officeName, staffId, staffDisplayName,
|
||||
organisationalRole, roles, permissions, principal.getId(), authentication.getToken().getTokenValue(),
|
||||
requireTwoFactorAuth);
|
||||
}
|
||||
|
||||
return this.apiJsonSerializerService.serialize(authenticatedUserData);
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.fineract.infrastructure.security.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
|
||||
public class FineractJwtAuthenticationToken extends JwtAuthenticationToken {
|
||||
|
||||
private final UserDetails user;
|
||||
|
||||
public FineractJwtAuthenticationToken(Jwt jwt, Collection<GrantedAuthority> authorities, UserDetails user) {
|
||||
super(jwt, authorities, user.getUsername());
|
||||
this.user = Objects.requireNonNull(user, "user");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails getPrincipal() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
+16
-11
@@ -20,12 +20,13 @@ package org.apache.fineract.infrastructure.security.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -58,18 +60,21 @@ public class InsecureTwoFactorAuthenticationFilter extends TwoFactorAuthenticati
|
||||
}
|
||||
|
||||
// Add two-factor authenticated authority if user is authenticated
|
||||
if (authentication != null && authentication.isAuthenticated() && authentication.getPrincipal() instanceof AppUser) {
|
||||
AppUser user = (AppUser) authentication.getPrincipal();
|
||||
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (authentication != null && authentication.isAuthenticated()) {
|
||||
List<GrantedAuthority> updatedAuthorities = new ArrayList<>(authentication.getAuthorities());
|
||||
updatedAuthorities.add(new SimpleGrantedAuthority("TWOFACTOR_AUTHENTICATED"));
|
||||
UsernamePasswordAuthenticationToken updatedAuthentication = new UsernamePasswordAuthenticationToken(
|
||||
authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities);
|
||||
context.setAuthentication(updatedAuthentication);
|
||||
|
||||
if (authentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
UsernamePasswordAuthenticationToken updatedAuthentication = new UsernamePasswordAuthenticationToken(
|
||||
authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities);
|
||||
context.setAuthentication(updatedAuthentication);
|
||||
} else if (authentication instanceof FineractJwtAuthenticationToken) {
|
||||
FineractJwtAuthenticationToken fineractJwtAuthenticationToken = (FineractJwtAuthenticationToken) authentication;
|
||||
FineractJwtAuthenticationToken updatedAuthentication = new FineractJwtAuthenticationToken(
|
||||
fineractJwtAuthenticationToken.getToken(), (Collection<GrantedAuthority>) updatedAuthorities,
|
||||
(UserDetails) authentication.getPrincipal());
|
||||
context.setAuthentication(updatedAuthentication);
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(req, res);
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||
*
|
||||
* Used to support Oauth2 authentication and the service is loaded only when "oauth" profile is active.
|
||||
*/
|
||||
@Service(value = "tenantIdentifierProcessingFilter")
|
||||
@Service
|
||||
@Profile("oauth")
|
||||
public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
|
||||
|
||||
|
||||
+17
-12
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.security.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -28,6 +29,7 @@ import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.fineract.infrastructure.security.constants.TwoFactorConstants;
|
||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||
import org.apache.fineract.infrastructure.security.domain.TFAccessToken;
|
||||
import org.apache.fineract.infrastructure.security.service.TwoFactorService;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
@@ -39,7 +41,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
@@ -106,25 +108,28 @@ public class TwoFactorAuthenticationFilter extends GenericFilterBean {
|
||||
|
||||
List<GrantedAuthority> updatedAuthorities = new ArrayList<>(authentication.getAuthorities());
|
||||
updatedAuthorities.add(new SimpleGrantedAuthority("TWOFACTOR_AUTHENTICATED"));
|
||||
final Authentication updatedAuthentication = createUpdatedAuthentication(authentication, updatedAuthorities);
|
||||
context.setAuthentication(updatedAuthentication);
|
||||
context.setAuthentication(createUpdatedAuthentication(authentication, updatedAuthorities));
|
||||
}
|
||||
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // TODO FINERACT-1012
|
||||
private Authentication createUpdatedAuthentication(final Authentication currentAuthentication,
|
||||
final List<GrantedAuthority> updatedAuthorities) {
|
||||
final List<GrantedAuthority> updatedAuthorities) throws ServletException {
|
||||
|
||||
final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
currentAuthentication.getPrincipal(), currentAuthentication.getCredentials(), updatedAuthorities);
|
||||
|
||||
if (currentAuthentication instanceof OAuth2Authentication) {
|
||||
final OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) currentAuthentication;
|
||||
return new OAuth2Authentication(oAuth2Authentication.getOAuth2Request(), authentication);
|
||||
if (currentAuthentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
UsernamePasswordAuthenticationToken updatedAuthentication = new UsernamePasswordAuthenticationToken(
|
||||
currentAuthentication.getPrincipal(), currentAuthentication.getCredentials(), updatedAuthorities);
|
||||
return updatedAuthentication;
|
||||
} else if (currentAuthentication instanceof FineractJwtAuthenticationToken) {
|
||||
FineractJwtAuthenticationToken fineractJwtAuthenticationToken = (FineractJwtAuthenticationToken) currentAuthentication;
|
||||
FineractJwtAuthenticationToken updatedAuthentication = new FineractJwtAuthenticationToken(
|
||||
fineractJwtAuthenticationToken.getToken(), (Collection<GrantedAuthority>) updatedAuthorities,
|
||||
(UserDetails) currentAuthentication.getPrincipal());
|
||||
return updatedAuthentication;
|
||||
} else {
|
||||
throw new ServletException("Unknown authentication type: " + currentAuthentication.getClass().getName());
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -19,7 +19,6 @@
|
||||
package org.apache.fineract.portfolio.self.security.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@@ -28,7 +27,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.apache.fineract.infrastructure.security.api.UserDetailsApiResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -57,8 +55,7 @@ public class SelfUserDetailsApiResource {
|
||||
+ "For more info visit this link - https://demo.fineract.dev/fineract-provider/api-docs/apiLive.htm#selfoauth")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SelfUserDetailsApiResourceSwagger.GetSelfUserDetailsResponse.class))) })
|
||||
public String fetchAuthenticatedUserData(
|
||||
@QueryParam("access_token") @Parameter(description = "äccess_token") final String accessToken) {
|
||||
return this.userDetailsApiResource.fetchAuthenticatedUserData(accessToken);
|
||||
public String fetchAuthenticatedUserData() {
|
||||
return this.userDetailsApiResource.fetchAuthenticatedUserData();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user