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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/security/oauth2
|
||||
https://www.springframework.org/schema/security/spring-security-oauth2.xsd
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<beans:beans profile="oauth">
|
||||
<http create-session="stateless" use-expressions="true" pattern="/api/v1/**"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint"
|
||||
access-decision-manager-ref="accessDecisionManager">
|
||||
<csrf disabled="true"/>
|
||||
<anonymous enabled="false" />
|
||||
<intercept-url pattern="/api//v1/**" method="OPTIONS"
|
||||
access="permitAll" requires-channel="https" />
|
||||
<intercept-url pattern="/api/*/twofactor" access="isFullyAuthenticated()"
|
||||
method="GET" requires-channel="https" />
|
||||
<intercept-url pattern="/api/*/twofactor" access="isFullyAuthenticated()"
|
||||
method="POST" requires-channel="https" />
|
||||
<intercept-url pattern="/api/*/twofactor/validate" access="isFullyAuthenticated()"
|
||||
method="POST" requires-channel="https" />
|
||||
<intercept-url pattern="/api/v1/**" access="isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')"
|
||||
method="GET" requires-channel="https" />
|
||||
<intercept-url pattern="/api/v1/**" access="isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')"
|
||||
method="POST" requires-channel="https" />
|
||||
<intercept-url pattern="/api/v1/**" access="isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')"
|
||||
method="PUT" requires-channel="https" />
|
||||
<intercept-url pattern="/api/v1/**" access="isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')"
|
||||
method="DELETE" requires-channel="https" />
|
||||
<intercept-url pattern="/api/v1/**" access="isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')"
|
||||
method="HEAD" requires-channel="https" />
|
||||
<custom-filter ref="tenantIdentifierProcessingFilter"
|
||||
position="FIRST" />
|
||||
<custom-filter before="PRE_AUTH_FILTER" ref="resourceServerFilter" />
|
||||
<custom-filter ref="twoFactorAuthFilter" after="BASIC_AUTH_FILTER" />
|
||||
<access-denied-handler ref="oauthAccessDeniedHandler" />
|
||||
</http>
|
||||
|
||||
<http pattern="/api/oauth/token" create-session="stateless"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint" use-expressions="true"
|
||||
authentication-manager-ref="clientAuthenticationManager">
|
||||
<csrf disabled="true"/>
|
||||
<intercept-url pattern="/api/oauth/token" method="OPTIONS"
|
||||
access="permitAll" requires-channel="https" />
|
||||
<intercept-url pattern="/api/oauth/token" method="POST"
|
||||
access="isFullyAuthenticated()" requires-channel="https" />
|
||||
<anonymous enabled="false" />
|
||||
|
||||
<custom-filter ref="tenantIdentifierProcessingFilter"
|
||||
position="FIRST" />
|
||||
<custom-filter ref="clientCredentialsTokenEndpointFilter"
|
||||
before="BASIC_AUTH_FILTER" />
|
||||
<access-denied-handler ref="oauthAccessDeniedHandler" />
|
||||
</http>
|
||||
|
||||
<beans:bean id="oauthAuthenticationEntryPoint"
|
||||
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
|
||||
<beans:property name="realmName" value="Fineract Platform API" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="oauthAccessDeniedHandler"
|
||||
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
|
||||
|
||||
<beans:bean id="clientCredentialsTokenEndpointFilter"
|
||||
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
|
||||
<beans:constructor-arg value="/api/oauth/token" />
|
||||
<beans:property name="authenticationManager" ref="clientAuthenticationManager" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="accessDecisionManager"
|
||||
class="org.springframework.security.access.vote.UnanimousBased">
|
||||
<beans:constructor-arg>
|
||||
<beans:list>
|
||||
<beans:bean
|
||||
class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
|
||||
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
|
||||
<beans:bean
|
||||
class="org.springframework.security.access.vote.AuthenticatedVoter" />
|
||||
<beans:bean
|
||||
class="org.springframework.security.web.access.expression.WebExpressionVoter" />
|
||||
<beans:bean
|
||||
class="org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote" />
|
||||
</beans:list>
|
||||
</beans:constructor-arg>
|
||||
</beans:bean>
|
||||
|
||||
<authentication-manager id="clientAuthenticationManager" erase-credentials="false">
|
||||
<authentication-provider user-service-ref="clientDetailsUserService" />
|
||||
<authentication-provider ref="customAuthenticationProvider" />
|
||||
</authentication-manager>
|
||||
|
||||
<beans:bean id="clientDetailsUserService"
|
||||
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
|
||||
<beans:constructor-arg ref="clientDetailsService" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="clientDetailsService"
|
||||
class="org.springframework.security.oauth2.provider.client.JdbcClientDetailsService">
|
||||
<beans:constructor-arg ref="routingDataSource" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="tokenStore"
|
||||
class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
|
||||
<beans:constructor-arg ref="routingDataSource" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="tokenServices"
|
||||
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
|
||||
<beans:property name="tokenStore" ref="tokenStore" />
|
||||
<beans:property name="clientDetailsService" ref="clientDetailsService" />
|
||||
<beans:property name="supportRefreshToken" value="true" />
|
||||
<beans:property name="refreshTokenValiditySeconds"
|
||||
value="86400" />
|
||||
<beans:property name="accessTokenValiditySeconds"
|
||||
value="3600" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="userApprovalHandler"
|
||||
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
|
||||
<beans:property name="tokenStore" ref="tokenStore" />
|
||||
<beans:property name="clientDetailsService" ref="clientDetailsService" />
|
||||
<beans:property name="requestFactory" ref="oAuth2RequestFactory" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="oAuth2RequestFactory"
|
||||
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
|
||||
<beans:constructor-arg ref="clientDetailsService" />
|
||||
</beans:bean>
|
||||
|
||||
<oauth:authorization-server
|
||||
client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"
|
||||
user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/api/oauth/token"
|
||||
authorization-endpoint-url="/api/oauth/authorize">
|
||||
<oauth:refresh-token />
|
||||
<oauth:password />
|
||||
</oauth:authorization-server>
|
||||
|
||||
<oauth:resource-server id="resourceServerFilter" stateless="false"
|
||||
token-services-ref="tokenServices" />
|
||||
</beans:beans>
|
||||
</beans:beans>
|
||||
@@ -2769,22 +2769,6 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#authenticationoauth">Authentication Oauth2</a></td>
|
||||
<td>oauth/token</td>
|
||||
<td><a href="#oauth">OAuth2 Access and refresh Token Request</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><a href="#oauth_access_token_req">OAuth2 Access Token Request from refresh token</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>authenticated user</td>
|
||||
<td></td>
|
||||
<td><a href="#userdetails_request">Fetch Authenticated user details</a></td>
|
||||
@@ -4499,7 +4483,7 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti
|
||||
function getOauthToken(username, password) {
|
||||
|
||||
var jqxhr = $.ajax({
|
||||
url : "/fineract-provider/api/oauth/token",
|
||||
url : "URL of the authentication server",
|
||||
type : 'POST',
|
||||
dataType : 'json',
|
||||
data : {
|
||||
@@ -39103,174 +39087,6 @@ No Request Body
|
||||
<div class="method-description">
|
||||
<h3>Authentication Oauth2</h3>
|
||||
<p>An API capability that allows client applications to fetch current user details details using Oauth2.</p>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="fineractHeading2">Field Descriptions</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>accessToken</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>HTTP Auth bearer key. See <a
|
||||
href="#authentication_overview">Authentication Overview</a> for
|
||||
an example of its use.
|
||||
</td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="oauth" name="oauth" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Authentication via OAuth2</h3>
|
||||
<p>API for requesting OAuth2 access token and refresh token.</p>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="fineractHeading2">Field Descriptions</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>grant_type</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Indicates the requested grant type. Supported values:
|
||||
<span>password</span>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>client_id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Indicates the client application identity.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>client_secret</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Optional field.
|
||||
Indicates the client application password.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>username</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Application User(resource) login name.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>password</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Application User(resource) password.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="oauth_request" name="oauth_request" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>OAuth2 Refresh and Access Token Request</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/oauth/token?username={username}&password={password}&client_id={clientId}&grant_type={grant_type}&client_secret={client_secret}
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST api/oauth/token?username=mifos&password=password&client_id=community-app&grant_type=password&client_secret=123
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
""access_token": "b771987f-82fc-45ba-b521-bfe280c4e603",
|
||||
"token_type": "bearer",
|
||||
"refresh_token":"a2a89b23-8d22-4d90-8585-8f464db433b0",
|
||||
"expires_in": 3599,
|
||||
"scope": "all"
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a id="oauth_access_token_req" name="oauth_access_token_req" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Authentication via OAuth2</h3>
|
||||
<p>API for requesting OAuth2 access tokens through oAuth2 refresh tokens.</p>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="fineractHeading2">Field Descriptions</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>grant_type</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Indicates the requested grant type. Supported values:
|
||||
<span>refresh_token</span>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>client_id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Indicates the client application identity.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>client_secret</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Optional field.
|
||||
Indicates the client application password.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>refresh_token</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Mandatory field.
|
||||
Application refresh token to generate access token.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="oauth_request_with_refresh" name="oauth_request_with_refresh" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>OAuth2 Token Request through Refresh Token</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/oauth/token?refresh_token={refresh_token}&client_id={clientId}&grant_type={grant_type}&client_secret={client_secret}
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST api/oauth/token?client_id=community-app&grant_type=refresh_token&client_secret=123&refresh_token=a2a89b23-8d22-4d90-8585-8f464db433b0
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
""access_token": "b771987f-82fc-45ba-b521-bfe280c4e643",
|
||||
"token_type": "bearer",
|
||||
"refresh_token":"a2a89b23-8d22-4d90-8585-8f464db433b0",
|
||||
"expires_in": 3599,
|
||||
"scope": "all"
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39282,10 +39098,10 @@ No Request Body
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/v1/userdetails?access_token={access_token}
|
||||
GET https://DomainName/api/v1/userdetails
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST userdetails?access_token=bWlmb3M6cGFzc3dvcmQ=
|
||||
GET userdetails
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
@@ -39342,22 +39158,6 @@ No Request Body
|
||||
|
||||
|
||||
|
||||
|
||||
<code class="method-request">
|
||||
POST api/oauth/token?username=mifos&password=password&client_id=community-app&grant_type=password&client_secret=123
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"developerMessage": "Invalid authentication details were passed in api request.",
|
||||
"developerDocLink": "https://github.com/openMF/mifosx/wiki/HTTP-API-Error-codes",
|
||||
"httpStatusCode": "401",
|
||||
"defaultUserMessage": "Unauthenticated. Please login.",
|
||||
"userMessageGlobalisationCode": "error.msg.not.authenticated",
|
||||
"errors": []
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47220,10 +47020,10 @@ No Request Body
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/v1/self/userdetails?access_token={access_token}
|
||||
POST https://DomainName/api/v1/self/userdetails
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST self/userdetails?access_token=bWlmb3M6cGFzc3dvcmQ=
|
||||
POST self/userdetails
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
@@ -47258,21 +47058,6 @@ No Request Body
|
||||
}
|
||||
</code>
|
||||
|
||||
<code class="method-request">
|
||||
POST api/oauth/token?username=mifos&password=password&client_id=community-app&grant_type=password&client_secret=123
|
||||
Content-Type: application/json
|
||||
No Request Body
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"developerMessage": "Invalid authentication details were passed in api request.",
|
||||
"developerDocLink": "https://github.com/openMF/mifosx/wiki/HTTP-API-Error-codes",
|
||||
"httpStatusCode": "401",
|
||||
"defaultUserMessage": "Unauthenticated. Please login.",
|
||||
"userMessageGlobalisationCode": "error.msg.not.authenticated",
|
||||
"errors": []
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user