diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/Utils.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/Utils.java index cf4ee6630bb..68142e01d40 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/Utils.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/Utils.java @@ -34,6 +34,7 @@ import java.util.TimeZone; import com.jayway.restassured.RestAssured; +import com.jayway.restassured.http.ContentType; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; import com.jayway.restassured.specification.RequestSpecification; @@ -62,7 +63,7 @@ public class Utils { public static final String TENANT_TIME_ZONE = "Asia/Kolkata"; private static final String HEALTH_URL = "/fineract-provider/actuator/health"; - private static final String LOGIN_URL = "/fineract-provider/api/v1/authentication?username=mifos&password=password&" + TENANT_IDENTIFIER; + private static final String LOGIN_URL = "/fineract-provider/api/v1/authentication?" + TENANT_IDENTIFIER; public static void initializeRESTAssured() { RestAssured.baseURI = "https://localhost"; @@ -116,9 +117,13 @@ public static String loginIntoServerAndGetBase64EncodedAuthenticationKey() { try { logger.info("Logging in, for integration test..."); System.out.println("-----------------------------------LOGIN-----------------------------------------"); - final String json = RestAssured.post(LOGIN_URL).asString(); + String json = RestAssured.given().contentType(ContentType.JSON) + .body("{\"username\":\"mifos\", \"password\":\"password\"}") + .expect().log().ifError().when().post(LOGIN_URL).asString(); assertThat("Failed to login into fineract platform", StringUtils.isBlank(json), is(false)); - return JsonPath.with(json).get("base64EncodedAuthenticationKey"); + String key = JsonPath.with(json).get("base64EncodedAuthenticationKey"); + assertThat("Failed to obtain key: " + json, StringUtils.isBlank(key), is(false)); + return key; } catch (final Exception e) { if (e instanceof HttpHostConnectException) { final HttpHostConnectException hh = (HttpHostConnectException) e; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java index c99a4fd4780..7ddf2f8f0c4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Set; +import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -48,15 +49,22 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; +import com.google.gson.Gson; + import com.sun.jersey.core.util.Base64; -@Path("/authentication") @Component -@Profile("basicauth") @Scope("singleton") +@Profile("basicauth") +@Path("/authentication") @Api(value = "Authentication HTTP Basic", description = "An API capability that allows client applications to verify authentication details using HTTP Basic Authentication.") public class AuthenticationApiResource { + public static class AuthenticateRequest { + public String username; + public String password; + } + private final DaoAuthenticationProvider customAuthenticationProvider; private final ToApiJsonSerializer apiJsonSerializerService; private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext; @@ -74,16 +82,25 @@ public AuthenticationApiResource( } @POST + @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @ApiOperation(value = "Verify authentication", notes = "Authenticates the credentials provided and returns the set roles and permissions allowed.") @ApiResponses({@ApiResponse(code = 200, message = "", response = AuthenticationApiResourceSwagger.PostAuthenticationResponse.class), @ApiResponse(code = 400, message = "Unauthenticated. Please login")}) - public String authenticate(@QueryParam("username") @ApiParam(value = "username") final String username, @QueryParam("password") @ApiParam(value = "password") final String password) { + public String authenticate(final String apiRequestBodyAsJson) { + // TODO FINERACT-819: sort out Jersey so JSON conversion does not have to be done explicitly via GSON here, but implicit by arg + AuthenticateRequest request = new Gson().fromJson(apiRequestBodyAsJson, AuthenticateRequest.class); + if (request == null) { + throw new IllegalArgumentException("Invalid JSON in BODY (no longer URL param; see FINERACT-726) of POST to /authentication: " + apiRequestBodyAsJson); + } + if (request.username == null || request.password == null) { + throw new IllegalArgumentException("Username or Password is null in JSON (see FINERACT-726) of POST to /authentication: " + apiRequestBodyAsJson + "; username=" + request.username + ", password=" + request.password); + } - final Authentication authentication = new UsernamePasswordAuthenticationToken(username, password); + final Authentication authentication = new UsernamePasswordAuthenticationToken(request.username, request.password); final Authentication authenticationCheck = this.customAuthenticationProvider.authenticate(authentication); final Collection permissions = new ArrayList<>(); - AuthenticatedUserData authenticatedUserData = new AuthenticatedUserData(username, permissions); + AuthenticatedUserData authenticatedUserData = new AuthenticatedUserData(request.username, permissions); if (authenticationCheck.isAuthenticated()) { final Collection authorities = new ArrayList<>(authenticationCheck.getAuthorities()); @@ -91,7 +108,7 @@ public String authenticate(@QueryParam("username") @ApiParam(value = "username") permissions.add(grantedAuthority.getAuthority()); } - final byte[] base64EncodedAuthenticationKey = Base64.encode(username + ":" + password); + final byte[] base64EncodedAuthenticationKey = Base64.encode(request.username + ":" + request.password); final AppUser principal = (AppUser) authenticationCheck.getPrincipal(); final Collection roles = new ArrayList<>(); @@ -111,11 +128,11 @@ public String authenticate(@QueryParam("username") @ApiParam(value = "username") boolean isTwoFactorRequired = twoFactorUtils.isTwoFactorAuthEnabled() && ! principal.hasSpecificPermissionTo(TwoFactorConstants.BYPASS_TWO_FACTOR_PERMISSION); if (this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)) { - authenticatedUserData = new AuthenticatedUserData(username, principal.getId(), + authenticatedUserData = new AuthenticatedUserData(request.username, principal.getId(), new String(base64EncodedAuthenticationKey), isTwoFactorRequired); } else { - authenticatedUserData = new AuthenticatedUserData(username, officeId, officeName, staffId, staffDisplayName, + authenticatedUserData = new AuthenticatedUserData(request.username, officeId, officeName, staffId, staffDisplayName, organisationalRole, roles, permissions, principal.getId(), new String(base64EncodedAuthenticationKey), isTwoFactorRequired); } @@ -124,4 +141,4 @@ public String authenticate(@QueryParam("username") @ApiParam(value = "username") return this.apiJsonSerializerService.serialize(authenticatedUserData); } -} \ No newline at end of file +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java index b5b6671b49e..d1bd98abf0a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/security/api/SelfAuthenticationApiResource.java @@ -25,16 +25,17 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -@Path("/self/authentication") @Component -@Profile("basicauth") @Scope("singleton") +@Profile("basicauth") +@Path("/self/authentication") @Api(value = "Self Authentication", description = "") public class SelfAuthenticationApiResource { @@ -47,12 +48,11 @@ public SelfAuthenticationApiResource( } @POST + @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @ApiOperation(value = "Verify authentication", httpMethod = "POST", notes = "Authenticates the credentials provided and returns the set roles and permissions allowed.\n\n" + "Please visit this link for more info - https://demo.openmf.org/api-docs/apiLive.htm#selfbasicauth") @ApiResponses({@ApiResponse(code = 200, message = "OK", response = SelfAuthenticationApiResourceSwagger.PostSelfAuthenticationResponse.class)}) - public String authenticate(@QueryParam("username") @ApiParam(value = "username") final String username, - @QueryParam("password") @ApiParam(value = "password") final String password) { - return this.authenticationApiResource.authenticate(username, password); + public String authenticate(final String apiRequestBodyAsJson) { + return this.authenticationApiResource.authenticate(apiRequestBodyAsJson); } - }