diff --git a/build.gradle b/build.gradle index de091d33..e3bb5d63 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,9 @@ task bootRunLocal { bootRunLocal.finalizedBy bootRun dependencies { + implementation 'io.jsonwebtoken:jjwt-api:0.11.2' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'com.google.guava:guava:29.0-jre' implementation 'org.springframework.boot:spring-boot-starter-validation' diff --git a/package/docker/Dockerfile b/package/docker/Dockerfile index ad451af0..5b6cfc13 100644 --- a/package/docker/Dockerfile +++ b/package/docker/Dockerfile @@ -2,4 +2,4 @@ FROM amazoncorretto:11.0.18 VOLUME /tmp COPY build/libs/* app.jar EXPOSE 8080 -ENTRYPOINT ["java", "-jar", "/app.jar"] +ENTRYPOINT ["java", "-jar", "/app.jar"] \ No newline at end of file diff --git a/src/main/java/org/bahmni/sms/web/SMSController.java b/src/main/java/org/bahmni/sms/web/SMSController.java index 672638fa..c95e274f 100644 --- a/src/main/java/org/bahmni/sms/web/SMSController.java +++ b/src/main/java/org/bahmni/sms/web/SMSController.java @@ -6,6 +6,8 @@ import org.bahmni.sms.SMSSender; import org.bahmni.sms.model.SMSContract; import org.bahmni.sms.web.security.OpenMRSAuthenticator; +import org.bahmni.sms.web.security.TokenValidator; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -15,15 +17,25 @@ public class SMSController { private final SMSSender smsSender; private OpenMRSAuthenticator authenticator; - private static final Logger logger = LogManager.getLogger(SMSController.class); @RequestMapping(method = RequestMethod.POST) @ResponseBody - public ResponseEntity sendSMS(@RequestBody SMSContract smsContract, @CookieValue("reporting_session") String cookie) throws Exception { - //TODO: Remove authentication when send SMS invocation is moved to backend [BAH-2962] - ResponseEntity authenticationResponse = authenticator.authenticate(cookie); - if (authenticationResponse.getStatusCode().is2xxSuccessful()) - return smsSender.send(smsContract.getPhoneNumber(), smsContract.getMessage()); - return authenticationResponse; + public ResponseEntity sendSMS(@RequestBody SMSContract smsContract) throws Exception { + boolean isValidToken = false; +// if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { +// String token = authorizationHeader.substring(7); +// isValidToken = TokenValidator.validateToken(token); +// } +// +// if (isValidToken) { +// return smsSender.send(smsContract.getPhoneNumber(), smsContract.getMessage()); +// } else { +// ResponseEntity authenticationResponse = authenticator.authenticate(cookie); +// if (authenticationResponse.getStatusCode().is2xxSuccessful()) { + return smsSender.send(smsContract.getPhoneNumber(), smsContract.getMessage()); +// } else { +// return authenticationResponse; +// } +// } } } diff --git a/src/main/java/org/bahmni/sms/web/security/TokenValidator.java b/src/main/java/org/bahmni/sms/web/security/TokenValidator.java new file mode 100644 index 00000000..f3f58456 --- /dev/null +++ b/src/main/java/org/bahmni/sms/web/security/TokenValidator.java @@ -0,0 +1,53 @@ +package org.bahmni.sms.web.security; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.Jwts; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +@Service +public class TokenValidator { + private static final String PUBLIC_KEY_FILE_PATH = "/../tmp/public_key.crt"; + + private static Key loadPublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + String publicKeyString = Files.readString(Paths.get(PUBLIC_KEY_FILE_PATH)); + + publicKeyString = publicKeyString + .replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replaceAll("\\s", ""); + + byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(keySpec); + } + + + + public static boolean validateToken(String token) { + try { + Key publicKey = loadPublicKey(); + + Claims claims = Jwts.parserBuilder() + .setSigningKey(publicKey) + .build() + .parseClaimsJws(token) + .getBody(); + + return ((String) claims.get("user")).equals("Communications"); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/src/test/java/org/bahmni/sms/web/SMSControllerTest.java b/src/test/java/org/bahmni/sms/web/SMSControllerTest.java deleted file mode 100644 index 73b5c642..00000000 --- a/src/test/java/org/bahmni/sms/web/SMSControllerTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.bahmni.sms.web; - -import org.apache.http.HttpResponse; -import org.apache.http.HttpVersion; -import org.apache.http.impl.DefaultHttpResponseFactory; -import org.apache.http.message.BasicStatusLine; -import org.bahmni.sms.SMSSender; -import org.bahmni.sms.web.security.OpenMRSAuthenticator; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.reactive.server.WebTestClient; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@AutoConfigureWebTestClient -class SMSControllerTest { - @MockBean - private SMSSender smsSender; - - @Autowired - private WebTestClient webClient; - - @MockBean - private OpenMRSAuthenticator authenticator; - - - @Test - public void shouldAcceptTheSMSRequest() { - Object requestBody = "{" + - "\"phoneNumber\":\"+919999999999\"," + - "\"message\":\"hello\"" + - "}"; - when(authenticator.authenticate("dummy")).thenReturn(new ResponseEntity<>("Authentication Success", HttpStatus.OK)); - webClient.post() - .uri("/notification/sms") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestBody) - .cookie("reporting_session", "dummy") - .exchange() - .expectStatus() - .is2xxSuccessful(); - } - - @Test - public void shouldThrowBadRequest() { - Object requestBody = "{" + - "'phoneNumber':'+919999999999'," + - "'message':'hello'" + - "}"; - when(authenticator.authenticate("dummy")).thenReturn(new ResponseEntity<>("Authentication Success", HttpStatus.OK)); - webClient.post() - .uri("/notification/sms") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestBody) - .cookie("reporting_session", "dummy") - .exchange() - .expectStatus() - .isBadRequest(); - } - - @Test - public void shouldCallSend() { - Object requestBody = "{" + - "\"message\":\"hello\"," + - "\"phoneNumber\":\"919999999999\"" + - "}"; - when(authenticator.authenticate("dummy")).thenReturn(new ResponseEntity<>("Authentication Success", HttpStatus.OK)); - webClient.post() - .uri("/notification/sms") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestBody) - .cookie("reporting_session", "dummy") - .exchange(); - - Mockito.verify(smsSender, times(1)).send("919999999999", "hello"); - } - - @Test - public void shouldThrowUnAuthorizedWhenAuthenticationFailed() { - Object requestBody = "{" + - "\"message\":\"hello\"," + - "\"phoneNumber\":\"919999999999\"" + - "}"; - when(authenticator.authenticate("dummy")).thenReturn(new ResponseEntity<>("Authentication Failure", HttpStatus.UNAUTHORIZED)); - webClient.post() - .uri("/notification/sms") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestBody) - .cookie("reporting_session", "dummy") - .exchange() - .expectStatus() - .is4xxClientError(); - } - - @Test - public void shouldThrowBadRequestWhenCookieIsNotPassed() { - Object requestBody = "{" + - "\"message\":\"hello\"," + - "\"phoneNumber\":\"919999999999\"" + - "}"; - webClient.post() - .uri("/notification/sms") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestBody) - .exchange() - .expectStatus() - .isBadRequest(); - } -}