From e8c93778e98e316cb0dcdfebd4502492455705d6 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 3 May 2020 19:58:42 +0300 Subject: [PATCH 01/82] Refactor java agent SN-1524 --- .gitignore | 6 + .settings/org.eclipse.jdt.apt.core.prefs | 2 + .settings/org.eclipse.jdt.core.prefs | 9 + .vscode/settings.json | 3 + LICENSE | 2 +- README.md | 81 ++-- akka-http/README.md | 120 ------ akka-http/pom.xml | 102 ----- .../securenative/java/akka/SnDirectives.scala | 54 --- pom.xml | 357 ++++++++++++------ sdk-base/pom.xml | 194 ---------- .../java/com/securenative/models/Event.java | 18 - .../com/securenative/models/EventOptions.java | 111 ------ .../java/com/securenative/models/Message.java | 27 -- .../com/securenative/models/RiskLevel.java | 7 - .../models/SecureNativeOptions.java | 94 ----- .../java/com/securenative/models/SnEvent.java | 287 -------------- .../java/com/securenative/models/User.java | 38 -- .../java/com/securenative/snlogic/Agent.java | 74 ---- .../securenative/snlogic/EventManager.java | 11 - .../java/com/securenative/snlogic/ISDK.java | 13 - .../securenative/snlogic/ImpotentLogger.java | 310 --------------- .../java/com/securenative/snlogic/Logger.java | 22 -- .../securenative/snlogic/SecureNative.java | 119 ------ .../securenative/snlogic/SnEventManager.java | 140 ------- .../java/com/securenative/snlogic/Utils.java | 222 ----------- .../com/securenative/snlogic/AgentTest.java | 37 -- .../snlogic/SecureNativeTest.java | 81 ---- .../snlogic/TestClassForByteBuddy.java | 11 - .../snlogic/TestClassForByteBuddy2.java | 9 - spring/pom.xml | 167 -------- .../spring/VerifyRequestMiddleware.java | 33 -- .../spring/VerifyWebHookMiddleware.java | 131 ------- .../snlogic/VerifyWebHookMiddlewareTest.java | 83 ---- src/.DS_Store | Bin 6148 -> 6148 bytes src/main/java/.DS_Store | Bin 6148 -> 6148 bytes .../java/com/securenative/ApiManager.java | 9 + .../java/com/securenative/ApiManagerImpl.java | 47 +++ .../java/com/securenative/EventManager.java | 14 + .../com/securenative/EventOptionsBuilder.java | 61 +++ src/main/java/com/securenative/Logger.java | 89 +++++ src/main/java/com/securenative/Maps.java | 31 ++ .../java/com/securenative/SecureNative.java | 93 +++++ .../SecureNativeEventManager.java | 139 +++++++ .../config/ConfigurationManager.java | 77 ++++ .../SecureNativeConfigurationBuilder.java | 117 ++++++ .../config/SecureNativeOptions.java | 98 +++++ .../context/SecureNativeContext.java | 81 ++++ .../context/SecureNativeContextBuilder.java | 77 ++++ .../com/securenative/enums}/ActionType.java | 2 +- .../java/com/securenative/enums/ApiRoute.java | 16 + .../com/securenative/enums}/EventTypes.java | 2 +- .../securenative/enums/FailoverStrategy.java | 6 + .../com/securenative/enums/RiskLevel.java | 27 ++ .../SecureNativeConfigException.java | 8 + .../exceptions/SecureNativeHttpException.java | 7 + .../SecureNativeInvalidOptionsException.java | 7 + .../SecureNativeInvalidUriException.java | 8 + .../SecureNativeParseException.java | 7 + .../exceptions/SecureNativeSDKException.java | 3 + .../com/securenative/http/HttpClient.java | 9 + .../com/securenative/http/HttpResponse.java | 23 ++ .../http/SecureNativeHTTPClient.java | 51 +++ .../com/securenative/models/ClientToken.java | 16 +- .../java/com/securenative/models/Device.java | 0 .../java/com/securenative/models/Event.java | 6 + .../com/securenative/models/EventOptions.java | 63 ++++ .../securenative/models/RequestContext.java | 116 ++++++ .../securenative/models/RequestOptions.java | 29 ++ .../com/securenative/models/SDKEvent.java | 86 +++++ .../com/securenative/models/UserTraits.java | 49 +++ .../com/securenative/models/VerifyResult.java | 19 +- .../com/securenative/utils/DateUtils.java | 17 + .../securenative/utils/EncryptionUtils.java | 97 +++++ .../java/com/securenative/utils/IPUtils.java | 46 +++ .../com/securenative/utils/RequestUtils.java | 67 ++++ .../securenative/utils/SignatureUtils.java | 44 +++ .../java/com/securenative/utils/Utils.java | 41 ++ .../com/securenative/ApiManagerImplTest.java | 236 ++++++++++++ .../com/securenative/EventManagerTest.java | 291 ++++++++++++++ .../com/securenative/SecureNativeTest.java | 135 +++++++ .../com/securenative/http/HTTPServerMock.java | 63 ++++ .../http/SecureNativeHTTPClientTest.java | 31 ++ .../com/securenative/models/SampleEvent.java | 18 + .../com/securenative/utils/DateUtilsTest.java | 31 ++ .../utils/EncryptionUtilsTest.java | 74 ++++ .../com/securenative/utils/IPUtilsTest.java | 67 ++++ .../utils/SignatureUtilsTest.java | 30 ++ src/test/resources/securenative.properties | 2 + 89 files changed, 3066 insertions(+), 2692 deletions(-) create mode 100644 .settings/org.eclipse.jdt.apt.core.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .vscode/settings.json delete mode 100644 akka-http/README.md delete mode 100644 akka-http/pom.xml delete mode 100644 akka-http/src/main/scala/com/securenative/java/akka/SnDirectives.scala delete mode 100644 sdk-base/pom.xml delete mode 100644 sdk-base/src/main/java/com/securenative/models/Event.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/EventOptions.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/Message.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/RiskLevel.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/SecureNativeOptions.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/SnEvent.java delete mode 100644 sdk-base/src/main/java/com/securenative/models/User.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/Agent.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/EventManager.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/ISDK.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/ImpotentLogger.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/Logger.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/SecureNative.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/SnEventManager.java delete mode 100644 sdk-base/src/main/java/com/securenative/snlogic/Utils.java delete mode 100644 sdk-base/test/main/java/com/securenative/snlogic/AgentTest.java delete mode 100644 sdk-base/test/main/java/com/securenative/snlogic/SecureNativeTest.java delete mode 100644 sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy.java delete mode 100644 sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy2.java delete mode 100644 spring/pom.xml delete mode 100644 spring/src/main/java/com/securenative/spring/VerifyRequestMiddleware.java delete mode 100644 spring/src/main/java/com/securenative/spring/VerifyWebHookMiddleware.java delete mode 100644 spring/src/test/java/com/securenative/snlogic/VerifyWebHookMiddlewareTest.java create mode 100644 src/main/java/com/securenative/ApiManager.java create mode 100644 src/main/java/com/securenative/ApiManagerImpl.java create mode 100644 src/main/java/com/securenative/EventManager.java create mode 100644 src/main/java/com/securenative/EventOptionsBuilder.java create mode 100644 src/main/java/com/securenative/Logger.java create mode 100644 src/main/java/com/securenative/Maps.java create mode 100644 src/main/java/com/securenative/SecureNative.java create mode 100644 src/main/java/com/securenative/SecureNativeEventManager.java create mode 100644 src/main/java/com/securenative/config/ConfigurationManager.java create mode 100644 src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java create mode 100644 src/main/java/com/securenative/config/SecureNativeOptions.java create mode 100644 src/main/java/com/securenative/context/SecureNativeContext.java create mode 100644 src/main/java/com/securenative/context/SecureNativeContextBuilder.java rename {sdk-base/src/main/java/com/securenative/models => src/main/java/com/securenative/enums}/ActionType.java (72%) create mode 100644 src/main/java/com/securenative/enums/ApiRoute.java rename {sdk-base/src/main/java/com/securenative/models => src/main/java/com/securenative/enums}/EventTypes.java (96%) create mode 100644 src/main/java/com/securenative/enums/FailoverStrategy.java create mode 100644 src/main/java/com/securenative/enums/RiskLevel.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeConfigException.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeHttpException.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeInvalidOptionsException.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeInvalidUriException.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeParseException.java rename {sdk-base/src => src}/main/java/com/securenative/exceptions/SecureNativeSDKException.java (98%) create mode 100644 src/main/java/com/securenative/http/HttpClient.java create mode 100644 src/main/java/com/securenative/http/HttpResponse.java create mode 100644 src/main/java/com/securenative/http/SecureNativeHTTPClient.java rename sdk-base/src/main/java/com/securenative/models/ClientFingerPrint.java => src/main/java/com/securenative/models/ClientToken.java (58%) rename {sdk-base/src => src}/main/java/com/securenative/models/Device.java (100%) create mode 100644 src/main/java/com/securenative/models/Event.java create mode 100644 src/main/java/com/securenative/models/EventOptions.java create mode 100644 src/main/java/com/securenative/models/RequestContext.java create mode 100644 src/main/java/com/securenative/models/RequestOptions.java create mode 100644 src/main/java/com/securenative/models/SDKEvent.java create mode 100644 src/main/java/com/securenative/models/UserTraits.java rename sdk-base/src/main/java/com/securenative/models/RiskResult.java => src/main/java/com/securenative/models/VerifyResult.java (59%) create mode 100644 src/main/java/com/securenative/utils/DateUtils.java create mode 100644 src/main/java/com/securenative/utils/EncryptionUtils.java create mode 100644 src/main/java/com/securenative/utils/IPUtils.java create mode 100644 src/main/java/com/securenative/utils/RequestUtils.java create mode 100644 src/main/java/com/securenative/utils/SignatureUtils.java create mode 100644 src/main/java/com/securenative/utils/Utils.java create mode 100644 src/test/java/com/securenative/ApiManagerImplTest.java create mode 100644 src/test/java/com/securenative/EventManagerTest.java create mode 100644 src/test/java/com/securenative/SecureNativeTest.java create mode 100644 src/test/java/com/securenative/http/HTTPServerMock.java create mode 100644 src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java create mode 100644 src/test/java/com/securenative/models/SampleEvent.java create mode 100644 src/test/java/com/securenative/utils/DateUtilsTest.java create mode 100644 src/test/java/com/securenative/utils/EncryptionUtilsTest.java create mode 100644 src/test/java/com/securenative/utils/IPUtilsTest.java create mode 100644 src/test/java/com/securenative/utils/SignatureUtilsTest.java create mode 100644 src/test/resources/securenative.properties diff --git a/.gitignore b/.gitignore index 146a7f2..4bb19c4 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,9 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +/target +/.classpath +/.project +*.iml +.idea diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 0000000..d4313d4 --- /dev/null +++ b/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=false diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..1b6e1ef --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1133129 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7f4ad0a..edac868 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 nevoalm +Copyright (c) 2019 SecureNative Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6c3e32c..a65e6c9 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,58 @@ - # Java SDK for SecureNative +[SecureNative](https://www.securenative.com/) performs user monitoring by analyzing user interactions with your application and various factors such as network, devices, locations and access patterns to stop and prevent account takeover attacks. -**[SecureNative](https://www.securenative.com/) is rethinking-security-as-a-service, disrupting the cyber security space and the way enterprises consume and implement security solutions.** - - -#SDK - -This Java sdk is very light, comes with only two dependencies (httpAsyncClient and Jackson). -In addition, you can find two modules that can help you: - -[Spring](https://github.com/securenative/securenative-java/tree/master/spring) or any web application that uses javax.servlet - -[akka-http](https://github.com/securenative/securenative-java/tree/master/akka-http) - -# Quickstart +## Install the SDK When using Maven, add the following dependency to your `pom.xml` file: ```xml - - com.securenative.java - sdk-base - 0.2.4 - + + com.securenative.java + sdk-base + LATEST + ``` -Gradle: - -compile group: 'com.securenative.java', name: 'sdk-base', version: 'LATEST' - +When using Gradle, add the following dependency to your `build.gradle` file: +```gradle +compile group: 'com.securenative.java', name: 'sdk-parent', version: '0.3.1', ext: 'pom' +``` +When using SBT, add the following dependency to your `build.sbt` file: +```sbt +libraryDependencies += "com.securenative.java" % "sdk-parent" % "0.3.1" pomOnly() +``` ## Initialize the SDK -Go to the settings page of your SecureNative account and find your **API KEY** +To get your *API KEY*, login to your SecureNative account and go to project settings page: -**Initialize using API KEY** +### Option 1: Initialize via Config file +SecureNative can automatically load your config from *securenative.properties* file or from the file that is specified in your *SECURENATIVE_CONFIG_FILE* env variable: ```java - secureNative = new SecureNative(API_KEY,new SecureNativeOptions()); +SecureNative secureNative = SecureNative.init(); ``` +### Option 2: Initialize via API Key -You can pass empty SecureNativeOptions object or you can set the following: +```java +SecureNative secureNative = SecureNative.init("YOUR_API_KEY"); +``` - api url - target url the events will be sent (https://api.securenative.com/collector/api/v1). - interval - minimum interval between sending events (1000ms). - max events - maximum events that will be sent (1000). - timeout - (1500 ms). +### Option 3: Initialize via ConfigurationBuilder +```java +SecureNative secureNative = SecureNative.init(SecureNative.configBuilder() + .withApiKey("API_KEY") + .withMaxEvents(10) + .withLogLevel("error") + .build()); +``` - ```java - secureNative = new SecureNative(API_KEY,new SecureNativeOptions( - "https://other.domain.com/collector/api/v1", - 1200, - 5000, - 2000 - )); - ``` +## Getting SecureNative instance +Once initialized, sdk will create a singleton instance which you can get: +```java +SecureNative secureNative = SecureNative.getInstance(); +``` ## Tracking events @@ -176,4 +173,8 @@ Apply our filter to verify the request is from us, example in spring: registrationBean.setFilter(customURLFilter); return registrationBean; } - ``` \ No newline at end of file + ``` + +[Spring](https://github.com/securenative/securenative-java/tree/master/spring) or any web application that uses javax.servlet + +[akka-http](https://github.com/securenative/securenative-java/tree/master/akka-http) \ No newline at end of file diff --git a/akka-http/README.md b/akka-http/README.md deleted file mode 100644 index b162bf1..0000000 --- a/akka-http/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# Akka Http for Secure Native -This module adds Akka Http (scala) directives to Secure Native SDK in order to easily integrate with Akka Http applications. - -## Quickstart -Download the latest version of the SDK to your favourite scala build system: - -#### Maven -``` - - com.securenative.java - akka-http - LATEST - -``` - -#### Gradle -`compile group: 'com.securenative.java', name: 'akka-http', version: 'LATEST'` - -#### SBT -`libraryDependencies += "com.securenative.java" % "akka-http" % "LATEST"` - -### Initialize the SDK -Create an instance (singleton) of the SecureNative object with your Api Key: -```scala -import com.securenative.snlogic.SecureNative -import com.securenative.models.SecureNativeOptions - -object Main { - val apiKey = "YOUR_API_KEY" - implicit val snSdk: SecureNative = new SecureNative(apiKey, new SecureNativeOptions()) -} -``` - -### Tracking Events -Secure Native let you send Async event that won't impact your regular flows, you may use our built in types (such as login, logout, etc...) -or using your own custom events. Secure Native needs these events in order to learn the user behaviour. -```scala -object Main { - val apiKey = "YOUR_API_KEY" - implicit val snSdk: SecureNative = new SecureNative(apiKey, new SecureNativeOptions()) - - def main(args: Array[String]): Unit = { - - def route = path("login") { - post { - // Add Secure Native event directive to automatically build your event from - // the http request: - SnDirectives.extractSnEvent(EventTypes.LOG_IN)(snSdk) { builder => - - /* YOUR LOGIN BUSINESS LOGIC */ - - val event = builder // You may change or add your custom fields to the builder - .withUser(new User("jas723h2", "Jack Jefferson", "jackje@gmail.com")) - .build() // Finally call the build method to create the event - - // Track the event using the SDK: - snSdk.track(event) - complete("SOMETHING") - } - } - } - } -} -``` - - -### Guarding Sensitive Operations -In order to guard sensitive resources you can use the `verify` method, which will return the risk score of the current user. -Allowing you to take a decision on how to act, for example when trying to delete project from github we can use the verify method before actually deleting the project -when getting the risk score you can decide if you want to allow/block the deletion. - -```scala -object Main { - val apiKey = "YOUR_API_KEY" - implicit val snSdk: SecureNative = new SecureNative(apiKey, new SecureNativeOptions()) - - def main(args: Array[String]): Unit = { - - def route = path("project") { - delete { - SnDirectives.extractSnEvent(EventTypes.LOG_IN)(snSdk) { builder => - val event = builder - .withUser(new User("jas723h2", "Jack Jefferson", "jackje@gmail.com")) - .build() // Finally call the build method to create the event - - val riskScore = snSdk.verify(event) - - if (riskScore.riskLevel == "high") { - /* Your blocking logic */ - } else { - /* Your allowing logic */ - }s - complete("SOMETHING") - } - } - } - } -} -``` - -### Accepting Webhooks from Secure Native -Secure Native can respond on real time to changes in risk score based on your sent events to get those real-time notification -you can create a new endpoint so we can call it when something happens. -In order to verify that the incoming request originated from Secure Native servers we have another directive that called `verifyWebhook`. -```scala -object Main { - val apiKey = "YOUR_API_KEY" - def main(args: Array[String]): Unit = { - - def route = path("riskscore") { - post { // it has to be a post endpoint - SnDirectives.verifyWebhook(apiKey) { body => - println(body) // the body will be passed only for Secure Native requests - complete(body) - } - } - } - } -} -``` \ No newline at end of file diff --git a/akka-http/pom.xml b/akka-http/pom.xml deleted file mode 100644 index 9986d1f..0000000 --- a/akka-http/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - sdk-parent - com.securenative.java - 0.3.0 - - 4.0.0 - - akka - jar - - - 1.6 - 1.6 - 2.15.2 - 2.12 - 10.0.0 - 2.5.13 - - - - - org.scala-lang - scala-library - ${scala-library.version}.6 - - - - com.securenative.java - sdk-base - 0.2.0 - - - - com.typesafe.akka - akka-http_${scala-library.version} - ${akka-http.version} - provided - - - - com.typesafe.akka - akka-stream_${scala-library.version} - ${akka.version} - provided - - - - - - - net.alchim31.maven - scala-maven-plugin - 3.2.2 - - - - compile - - - - attach-javadocs - - doc-jar - - - - attach-sources - - add-source - - - - - - maven-assembly-plugin - - - - your.MainClass - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - \ No newline at end of file diff --git a/akka-http/src/main/scala/com/securenative/java/akka/SnDirectives.scala b/akka-http/src/main/scala/com/securenative/java/akka/SnDirectives.scala deleted file mode 100644 index b5809f3..0000000 --- a/akka-http/src/main/scala/com/securenative/java/akka/SnDirectives.scala +++ /dev/null @@ -1,54 +0,0 @@ -package com.securenative.java.akka - -import akka.http.scaladsl.model.HttpRequest -import akka.http.scaladsl.server.directives.{BasicDirectives, MarshallingDirectives} -import akka.http.scaladsl.server.{Directive1, ValidationRejection} -import com.securenative.models.SnEvent.EventBuilder -import com.securenative.models.{EventTypes, SnEvent} -import com.securenative.snlogic.{SecureNative, Utils} - -object SnDirectives extends BasicDirectives with MarshallingDirectives { - private val DEFAULT_IP = "127.0.0.1" - private val utils = new Utils() - - def verifyWebhook(secret: String): Directive1[String] = extractRequest.flatMap { request => - entity(as[String]).flatMap { body => - val headerSig = request.getHeader(utils.SN_HEADER) - - if (!headerSig.isPresent) { - cancelRejection(ValidationRejection(s"Failed to extract ${utils.SN_HEADER} header from the request, this request cannot be validated and probably not sent from SecureNative.")) - } - - if (utils.isVerifiedSnRequest(body, headerSig.get().value(), secret)) { - provide(body) - } else { - provide(null) - } - } - } - - def extractSnEvent(eventType: EventTypes)(implicit sdk: SecureNative): Directive1[EventBuilder] = extractRequest.flatMap { request => - val builder = fromRequest(eventType, request) - provide(builder) - } - - private def fromRequest(eventName: EventTypes, httpRequest: HttpRequest)(implicit snSdk: SecureNative): SnEvent.EventBuilder = { - val headers = Map(httpRequest.headers.map { h => h.name.toLowerCase -> h.value }: _*) - val cookies = Map(httpRequest.cookies.map { c => c.name -> c.value }: _*) - - val ua = headers.getOrElse("user-agent", "") - - val utils = new Utils() - val ip = utils.remoteIpFromRequest(name => headers.getOrElse(name, DEFAULT_IP)) - val remoteIp = headers.getOrElse("remote-address", DEFAULT_IP) - val snCookie = cookies.getOrElse(snSdk.getDefaultCookieName, headers.getOrElse(utils.SN_HEADER, "")) - - val builder = new SnEvent.EventBuilder(eventName.getType) - .withCookieValue(snCookie) - .withIp(ip) - .withRemoteIP(remoteIp) - .withUserAgent(ua) - - builder - } -} diff --git a/pom.xml b/pom.xml index 4ce04af..db5238f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,32 +1,24 @@ - - + + + 4.0.0 - - com.securenative.java - sdk-parent + io.securenative + securenative-java + jar 0.3.0 https://github.com/securenative/securenative-java + + ${project.groupId}:${project.artifactId}:${project.version} + SecureNative user monitoring sdk. + The MIT License https://opensource.org/licenses/MIT - - - Nevo Elmalem - nevo@securenative.com - securenative - http://www.securenative.com - - - - scm:git:git://github.com/securenative/securenative-java.git - scm:git:ssh://github.com:securenative/securenative-java.git - http://github.com/securenative/securenative-java/tree/master - + ossrh @@ -37,110 +29,21 @@ https://oss.sonatype.org/service/local/staging/deploy/maven2 - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - maven-assembly-plugin - - - - your.MainClass - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - - sdk-base - spring - akka-http - - pom + + + SecureNative Dev Team + info@securenative.com + SecureNative + https://www.securenative.com + + + + + scm:git:git://github.com/securenative/securenative-java.git + scm:git:ssh://github.com:securenative/securenative-java.git + http://github.com/securenative/securenative-java/tree/master + 1.6 @@ -148,5 +51,213 @@ 0.2.3 + + + deploy + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + com.fasterxml.jackson.core + jackson-databind + 2.9.9.2 + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + org.apache.maven + maven-model + 3.0.2 + + + org.slf4j + slf4j-api + 1.7.12 + + + com.squareup.okhttp3 + okhttp + 4.5.0 + + + org.mockito + mockito-core + 2.21.0 + test + + + org.springframework + spring-test + 5.2.6.RELEASE + test + + + org.assertj + assertj-core + 3.15.0 + test + + + com.squareup.okhttp3 + mockwebserver + 4.6.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.7.0-M1 + test + + + org.junit.jupiter + junit-jupiter-api + 5.7.0-M1 + test + + + org.junit-pioneer + junit-pioneer + 0.5.1 + test + + + org.skyscreamer + jsonassert + 1.5.0 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + maven-deploy-plugin + 2.8.2 + + + default-deploy + deploy + + deploy + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + maven-assembly-plugin + + + + your.MainClass + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + \ No newline at end of file diff --git a/sdk-base/pom.xml b/sdk-base/pom.xml deleted file mode 100644 index 57c0248..0000000 --- a/sdk-base/pom.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - sdk-parent - com.securenative.java - 0.3.0 - - sdk-base - 4.0.0 - - ${project.artifactId} - Secure Native SDK in java - https://github.com/securenative/securenative-java - - - The MIT License - https://opensource.org/licenses/MIT - - - - - Nevo Elmalem - nevo@securenative.com - securenative - http://www.securenative.com - - - - scm:git:git://github.com/securenative/securenative-java.git - scm:git:ssh://github.com:securenative/securenative-java.git - http://github.com/securenative/securenative-java/tree/master - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - maven-assembly-plugin - - - - your.MainClass - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - - - - com.fasterxml.jackson.core - jackson-databind - 2.9.9.2 - - - junit - junit - 4.12 - test - - - org.mockito - mockito-core - 2.21.0 - test - - - org.apache.maven - maven-model - 3.0.2 - - - org.asynchttpclient - async-http-client - 2.2.0 - - - net.bytebuddy - byte-buddy-agent - 1.10.1 - compile - - - org.reflections - reflections - 0.9.11 - - - net.bytebuddy - byte-buddy - 1.9.16 - - - org.apache.logging.log4j - log4j-api - 2.11.2 - - - - \ No newline at end of file diff --git a/sdk-base/src/main/java/com/securenative/models/Event.java b/sdk-base/src/main/java/com/securenative/models/Event.java deleted file mode 100644 index 4bc99b8..0000000 --- a/sdk-base/src/main/java/com/securenative/models/Event.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.securenative.models; - -import java.util.Map; - -public interface Event { - String getEventType(); - String getCid(); - String getVid(); - String getFp(); - String getIp(); - String getRemoteIP(); - String getUserAgent(); - User getUser(); - Device getDevice(); - String getCookieName(); - String getCookieValue(); - Map getParams(); -} diff --git a/sdk-base/src/main/java/com/securenative/models/EventOptions.java b/sdk-base/src/main/java/com/securenative/models/EventOptions.java deleted file mode 100644 index 8d98417..0000000 --- a/sdk-base/src/main/java/com/securenative/models/EventOptions.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.securenative.models; - -import java.util.AbstractMap; -import java.util.List; - -public class EventOptions { - private String ip; - private String userAgent; - private String remoteIP; - private User user; - private Device device; - private String cookieName; - private String cookieValue; - private String eventType; - private List > params; - - public EventOptions(String ip, String remoteIP, String userAgent, Device device, User user, String cookieName, String cookieValue, String eventType, List> params) { - this.ip = ip; - this.remoteIP = remoteIP; - this.userAgent = userAgent; - this.device = device; - this.user = user; - this.cookieName = cookieName; - this.eventType = eventType; - this.params = params; - this.cookieValue = cookieValue; - } - - public EventOptions(String ip, String userAgent,String eventType) { - this.ip = ip; - this.userAgent = userAgent; - this.eventType = eventType; - } - - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUserAgent() { - return userAgent; - } - - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } - - public String getRemoteIP() { - return remoteIP; - } - - public void setRemoteIP(String remoteIP) { - this.remoteIP = remoteIP; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public Device getDevice() { - return device; - } - - public void setDevice(Device device) { - this.device = device; - } - - public String getCookieName() { - return cookieName; - } - - public void setCookieName(String cookieName) { - this.cookieName = cookieName; - } - public String getEventType() { - return eventType; - } - - public void setEventType(String eventType) { - this.eventType = eventType; - } - - public List> getParams() { - return params; - } - - public void setParams(List> params) { - this.params = params; - } - - public String getCookieValue() { - return cookieValue; - } - - public void setCookieValue(String cookieValue) { - this.cookieValue = cookieValue; - } - - - - - -} diff --git a/sdk-base/src/main/java/com/securenative/models/Message.java b/sdk-base/src/main/java/com/securenative/models/Message.java deleted file mode 100644 index c665d39..0000000 --- a/sdk-base/src/main/java/com/securenative/models/Message.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.securenative.models; - -public class Message { - private Event snEvent; - private String url; - - public Message(Event snEvent, String url) { - this.snEvent = snEvent; - this.url = url; - } - - public Event getSnEvent() { - return snEvent; - } - - public void setSnEvent(Event snEvent) { - this.snEvent = snEvent; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } -} diff --git a/sdk-base/src/main/java/com/securenative/models/RiskLevel.java b/sdk-base/src/main/java/com/securenative/models/RiskLevel.java deleted file mode 100644 index e6199b8..0000000 --- a/sdk-base/src/main/java/com/securenative/models/RiskLevel.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.securenative.models; - -public enum RiskLevel { - high, - low, - medium -} \ No newline at end of file diff --git a/sdk-base/src/main/java/com/securenative/models/SecureNativeOptions.java b/sdk-base/src/main/java/com/securenative/models/SecureNativeOptions.java deleted file mode 100644 index ea6485c..0000000 --- a/sdk-base/src/main/java/com/securenative/models/SecureNativeOptions.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.securenative.models; - -public class SecureNativeOptions { - private String apiUrl; - private int interval; - private long maxEvents; - private long timeout; - private Boolean autoSend; - private Boolean isSdkEnabled; - private Boolean debugMode; - - public SecureNativeOptions(){ - this.autoSend = true; - this.isSdkEnabled = true; - this.debugMode = false; - } - - public SecureNativeOptions(String apiUrl, int interval, long maxEvents, int timeout, boolean autoSend, boolean isSdkEnabled, boolean debugMode) { - this.interval = interval; - this.maxEvents = maxEvents; - this.apiUrl = apiUrl; - this.timeout = timeout; - this.autoSend = autoSend; - this.isSdkEnabled = isSdkEnabled; - this.debugMode = debugMode; - } - - public SecureNativeOptions(String apiUrl, int interval, long maxEvents, int timeout) { - this.interval = interval; - this.maxEvents = maxEvents; - this.apiUrl = apiUrl; - this.timeout = timeout; - this.autoSend = true; - this.isSdkEnabled = true; - this.debugMode = false; - - } - - public String getApiUrl() { - return apiUrl; - } - - public void setApiUrl(String apiUrl) { - this.apiUrl = apiUrl; - } - - public int getInterval() { - return interval; - } - - public void setInterval(int interval) { - this.interval = interval; - } - - public long getMaxEvents() { - return maxEvents; - } - - public void setMaxEvents(long maxEvents) { - this.maxEvents = maxEvents; - } - - public long getTimeout() { - return timeout; - } - - public void setTimeout(long timeout) { - this.timeout = timeout; - } - - public Boolean isAutoSend() { - return autoSend; - } - - public void setAutoSend(Boolean autoSend) { - this.autoSend = autoSend; - } - - public Boolean getSdkEnabled() { - return isSdkEnabled; - } - - public void setSdkEnabled(Boolean sdkEnabled) { - isSdkEnabled = sdkEnabled; - } - - public Boolean getDebugMode() { - return debugMode; - } - - public void setDebugMode(Boolean debugMode) { - this.debugMode = debugMode; - } -} diff --git a/sdk-base/src/main/java/com/securenative/models/SnEvent.java b/sdk-base/src/main/java/com/securenative/models/SnEvent.java deleted file mode 100644 index 5c53df2..0000000 --- a/sdk-base/src/main/java/com/securenative/models/SnEvent.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.securenative.models; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.securenative.exceptions.SecureNativeSDKException; -import com.securenative.snlogic.Utils; - -import java.nio.charset.Charset; -import java.time.Instant; -import java.util.*; - -public class SnEvent implements Event { - public enum ParamsKeys { - PARAM_1("param_1"), - PARAM_2("param_2"), - PARAM_3("param_3"), - PARAM_4("param_4"), - PARAM_5("param_5"), - PARAM_6("param_6"); - - private String param; - - ParamsKeys(String param) { - this.param = param; - } - @Override - public String toString(){ - return this.param; - } - } - protected static Set paramKeys = new HashSet(Arrays.asList(ParamsKeys.PARAM_1.name(),ParamsKeys.PARAM_2.name(),ParamsKeys.PARAM_3.name(),ParamsKeys.PARAM_4.name(),ParamsKeys.PARAM_5.name(),ParamsKeys.PARAM_6.name())); - - private final static Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); - - private String eventType; - private String cid; - private String vid; - private String fp; - private String ip; - private String remoteIP; - private String userAgent; - private User user; - private long ts; - private Device device; - private String CookieName; - private String CookieValue; - private Map params; - - public static class EventBuilder { - private String eventType; - private String cid; - private String fp; - private String ip; - private String remoteIP; - private String userAgent; - private User user; - private Device device; - private String cookieName; - private String cookieValue; - private Utils utils; - private Map params; - - - public EventBuilder(String eventType) { - this.eventType = eventType; - this.utils = new Utils(); - } - - - public EventBuilder withCid(String cid) { - this.cid = cid; - return this; - } - - public EventBuilder withFp(String fp) { - this.fp = fp; - return this; - } - - public EventBuilder withIp(String ip) { - this.ip = ip; - return this; - } - - public EventBuilder withRemoteIP(String remoteIP) { - this.remoteIP = remoteIP; - return this; - } - - public EventBuilder withUserAgent(String userAgent) { - this.userAgent = userAgent; - return this; - } - - public EventBuilder withUser(User user) { - this.user = user; - return this; - } - - - public EventBuilder withDevice(Device device) { - this.device = device; - return this; - } - - public EventBuilder withCookieValue(String cookieBase64Value) { - if (this.utils.isNullOrEmpty(cookieBase64Value)) { - return this; - } - String decodedCookie = new String(Base64.getDecoder().decode(cookieBase64Value), DEFAULT_CHARSET); - ClientFingerPrint clientFP = this.parseClientFP(decodedCookie); - this.cookieValue = cookieBase64Value; - this.cid = clientFP != null ? clientFP.getCid() : ""; - this.fp = clientFP != null ? clientFP.getFp() : ""; - return this; - } - - public EventBuilder withParams(Map params) throws SecureNativeSDKException{ - if (params == null){ - params = new HashMap<>(); - params.put(ParamsKeys.PARAM_1.toString(),""); - params.put(ParamsKeys.PARAM_2.toString(),""); - params.put(ParamsKeys.PARAM_3.toString(),""); - params.put(ParamsKeys.PARAM_4.toString(),""); - params.put(ParamsKeys.PARAM_5.toString(),""); - params.put(ParamsKeys.PARAM_6.toString(),""); - } - else{ - Iterator i = params.keySet().iterator(); - while(i.hasNext()){ - if(!paramKeys.contains(i)){ - throw new SecureNativeSDKException("Key must be of param_1..param_6"); - } - } - } - this.params = params; - return this; - } - - public Event build() { - SnEvent event = new SnEvent(); - event.eventType = this.eventType; - event.cid = this.cid; - event.vid = UUID.randomUUID().toString(); - event.fp = this.fp; - event.ip = this.ip; - event.remoteIP = this.remoteIP; - event.userAgent = this.userAgent; - event.user = this.user; - event.ts = Instant.now().getEpochSecond(); - event.device = this.device; - event.CookieName = this.cookieName; - event.CookieValue = this.cookieValue; - event.params = this.params; - return event; - } - - private ClientFingerPrint parseClientFP(String json) { - if (this.utils.isNullOrEmpty(json)) { - return null; - } - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(json, ClientFingerPrint.class); - } catch (Exception e) { - return null; - } - } - - public String base64decode(String encodedString) { - if (this.utils.isNullOrEmpty(encodedString)) { - return ""; - } - return String.valueOf(Base64.getDecoder().decode(encodedString)); - } - } - - - private SnEvent() { - - } - - public String getEventType() { - return eventType; - } - - public void setEventType(String eventType) { - this.eventType = eventType; - } - - public String getCid() { - return cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - public String getVid() { - return vid; - } - - public void setVid(String vid) { - this.vid = vid; - } - - public String getFp() { - return fp; - } - - public void setFp(String fp) { - this.fp = fp; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getRemoteIP() { - return remoteIP; - } - - public void setRemoteIP(String remoteIP) { - this.remoteIP = remoteIP; - } - - public String getUserAgent() { - return userAgent; - } - - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public long getTs() { - return ts; - } - - public void setTs(long ts) { - this.ts = ts; - } - - public Device getDevice() { - return device; - } - - public void setDevice(Device device) { - this.device = device; - } - - - public String getCookieName() { - return CookieName; - } - - public void setCookieName(String cookieName) { - CookieName = cookieName; - } - - public String getCookieValue() { - return CookieValue; - } - - public void setCookieValue(String cookieValue) { - CookieValue = cookieValue; - } - - - public Map getParams() { - return params; - } - - public void setParams(Map params) { - this.params = params; - } -} diff --git a/sdk-base/src/main/java/com/securenative/models/User.java b/sdk-base/src/main/java/com/securenative/models/User.java deleted file mode 100644 index 686bb2b..0000000 --- a/sdk-base/src/main/java/com/securenative/models/User.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.securenative.models; - -public class User { - private String id; - private String name; - private String email; - - - public User(String id, String name, String email) { - this.id = id; - this.name = name; - this.email = email; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} diff --git a/sdk-base/src/main/java/com/securenative/snlogic/Agent.java b/sdk-base/src/main/java/com/securenative/snlogic/Agent.java deleted file mode 100644 index a9cc32b..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/Agent.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.securenative.snlogic; - -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.agent.ByteBuddyAgent; -import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; -import net.bytebuddy.implementation.MethodDelegation; -import org.apache.logging.log4j.util.ProcessIdUtil; -import org.reflections.Reflections; -import org.reflections.scanners.ResourcesScanner; - - -import java.lang.reflect.Field; -import java.util.*; -import java.util.regex.Pattern; - -import static net.bytebuddy.matcher.ElementMatchers.*; - -public class Agent { - - - public static String getPomXmlPaths() { - Reflections reflections = new Reflections(new ResourcesScanner()); - Set resources = reflections.getResources(Pattern.compile(".*jar")); - return resources.toString(); - } - - public static void changeClassMethod(Class cls, Class cls1, String methodName) { - ByteBuddyAgent.install(); - new ByteBuddy() - .redefine(cls) - .method(named(methodName) - .and(isDeclaredBy(cls) - .and(returns(String.class)))) - .intercept(MethodDelegation.to(cls1)) - .make() - .load(cls.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()) - .getLoaded(); - } - - public static Set scanAllClasses() { - Field f; - Set locations = new HashSet<>(); - try { - f = ClassLoader.class.getDeclaredField("classes"); - f.setAccessible(true); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - List classes = Collections.unmodifiableList((Vector) f.get(classLoader)); - for (Class next :classes){ - java.net.URL location = next.getResource('/' + next.getName().replace('.', - '/') + ".class"); - if (location != null && !Utils.isNullOrEmpty(location.getPath())){ - locations.add(location.getPath()); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return locations; - - } - - public static String readVersionInfoInManifest() { - Set locations = new HashSet<>(); - //build an object whose class is in the target jar - ProcessIdUtil object = new ProcessIdUtil(); - //navigate from its class object to a package object - Package objPackage = object.getClass().getPackage(); - //examine the package object - String name = objPackage.getSpecificationTitle(); - String version = objPackage.getSpecificationVersion(); - //some jars may use 'Implementation Version' entries in the manifest instead - return "Package name: " + name + ", Package version: " + version; - } -} diff --git a/sdk-base/src/main/java/com/securenative/snlogic/EventManager.java b/sdk-base/src/main/java/com/securenative/snlogic/EventManager.java deleted file mode 100644 index 1fcf82f..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/EventManager.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.securenative.snlogic; - - -import com.securenative.models.Event; -import com.securenative.models.RiskResult; - -public interface EventManager { - RiskResult sendSync(Event event, String requestUrl); - void sendAsync(Event event, String url); - -} diff --git a/sdk-base/src/main/java/com/securenative/snlogic/ISDK.java b/sdk-base/src/main/java/com/securenative/snlogic/ISDK.java deleted file mode 100644 index dfa1317..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/ISDK.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.securenative.snlogic; - - -import com.securenative.models.Event; -import com.securenative.models.RiskResult; - -public interface ISDK { - void track(Event event) throws Exception; - RiskResult verify(Event event); - RiskResult flow(long flowId, Event event); - String getApiKey(); - String getDefaultCookieName(); -} diff --git a/sdk-base/src/main/java/com/securenative/snlogic/ImpotentLogger.java b/sdk-base/src/main/java/com/securenative/snlogic/ImpotentLogger.java deleted file mode 100644 index 93781c4..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/ImpotentLogger.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.securenative.snlogic; - -import org.slf4j.Marker; - -public class ImpotentLogger implements org.slf4j.Logger { - @Override - public String getName() { - return null; - } - - @Override - public boolean isTraceEnabled() { - return false; - } - - @Override - public void trace(String s) { - - } - - @Override - public void trace(String s, Object o) { - - } - - @Override - public void trace(String s, Object o, Object o1) { - - } - - @Override - public void trace(String s, Object... objects) { - - } - - @Override - public void trace(String s, Throwable throwable) { - - } - - @Override - public boolean isTraceEnabled(Marker marker) { - return false; - } - - @Override - public void trace(Marker marker, String s) { - - } - - @Override - public void trace(Marker marker, String s, Object o) { - - } - - @Override - public void trace(Marker marker, String s, Object o, Object o1) { - - } - - @Override - public void trace(Marker marker, String s, Object... objects) { - - } - - @Override - public void trace(Marker marker, String s, Throwable throwable) { - - } - - @Override - public boolean isDebugEnabled() { - return false; - } - - @Override - public void debug(String s) { - - } - - @Override - public void debug(String s, Object o) { - - } - - @Override - public void debug(String s, Object o, Object o1) { - - } - - @Override - public void debug(String s, Object... objects) { - - } - - @Override - public void debug(String s, Throwable throwable) { - - } - - @Override - public boolean isDebugEnabled(Marker marker) { - return false; - } - - @Override - public void debug(Marker marker, String s) { - - } - - @Override - public void debug(Marker marker, String s, Object o) { - - } - - @Override - public void debug(Marker marker, String s, Object o, Object o1) { - - } - - @Override - public void debug(Marker marker, String s, Object... objects) { - - } - - @Override - public void debug(Marker marker, String s, Throwable throwable) { - - } - - @Override - public boolean isInfoEnabled() { - return false; - } - - @Override - public void info(String s) { - - } - - @Override - public void info(String s, Object o) { - - } - - @Override - public void info(String s, Object o, Object o1) { - - } - - @Override - public void info(String s, Object... objects) { - - } - - @Override - public void info(String s, Throwable throwable) { - - } - - @Override - public boolean isInfoEnabled(Marker marker) { - return false; - } - - @Override - public void info(Marker marker, String s) { - - } - - @Override - public void info(Marker marker, String s, Object o) { - - } - - @Override - public void info(Marker marker, String s, Object o, Object o1) { - - } - - @Override - public void info(Marker marker, String s, Object... objects) { - - } - - @Override - public void info(Marker marker, String s, Throwable throwable) { - - } - - @Override - public boolean isWarnEnabled() { - return false; - } - - @Override - public void warn(String s) { - - } - - @Override - public void warn(String s, Object o) { - - } - - @Override - public void warn(String s, Object... objects) { - - } - - @Override - public void warn(String s, Object o, Object o1) { - - } - - @Override - public void warn(String s, Throwable throwable) { - - } - - @Override - public boolean isWarnEnabled(Marker marker) { - return false; - } - - @Override - public void warn(Marker marker, String s) { - - } - - @Override - public void warn(Marker marker, String s, Object o) { - - } - - @Override - public void warn(Marker marker, String s, Object o, Object o1) { - - } - - @Override - public void warn(Marker marker, String s, Object... objects) { - - } - - @Override - public void warn(Marker marker, String s, Throwable throwable) { - - } - - @Override - public boolean isErrorEnabled() { - return false; - } - - @Override - public void error(String s) { - - } - - @Override - public void error(String s, Object o) { - - } - - @Override - public void error(String s, Object o, Object o1) { - - } - - @Override - public void error(String s, Object... objects) { - - } - - @Override - public void error(String s, Throwable throwable) { - - } - - @Override - public boolean isErrorEnabled(Marker marker) { - return false; - } - - @Override - public void error(Marker marker, String s) { - - } - - @Override - public void error(Marker marker, String s, Object o) { - - } - - @Override - public void error(Marker marker, String s, Object o, Object o1) { - - } - - @Override - public void error(Marker marker, String s, Object... objects) { - - } - - @Override - public void error(Marker marker, String s, Throwable throwable) { - - } -} diff --git a/sdk-base/src/main/java/com/securenative/snlogic/Logger.java b/sdk-base/src/main/java/com/securenative/snlogic/Logger.java deleted file mode 100644 index c08f0b1..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/Logger.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.securenative.snlogic; - -import org.slf4j.LoggerFactory; - -public class Logger{ - private static org.slf4j.Logger logger = new ImpotentLogger(); - - public static org.slf4j.Logger getLogger() { - return logger; - } - - public static void setLoggingEnable(boolean isLoggingEnabledInput) { - if(isLoggingEnabledInput){ - logger = LoggerFactory.getLogger(Logger.class); - logger.info("Secure Native logger is enabled"); - return; - } - logger = new ImpotentLogger(); - - } -} - diff --git a/sdk-base/src/main/java/com/securenative/snlogic/SecureNative.java b/sdk-base/src/main/java/com/securenative/snlogic/SecureNative.java deleted file mode 100644 index 04e48dd..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/SecureNative.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.securenative.snlogic; - - -import com.securenative.exceptions.SecureNativeSDKException; -import com.securenative.models.Event; -import com.securenative.models.RiskResult; -import com.securenative.models.SecureNativeOptions; - -public class SecureNative implements ISDK { - private final String API_URL = "https://api.securenative.com/collector/api/v1"; - private final int INTERVAL = 1000; - private final int MAX_EVENTS = 1000; - private final Boolean AUTO_SEND = true; - private final Boolean SDK_ENABLED = true; - private final Boolean DEBUG_LOG = false; - private final int DEFAULT_TIMEOUT = 1500; - - private EventManager eventManager; - private SecureNativeOptions snOptions; - private String apiKey; - private Utils utils; - - private static ISDK secureNative = null; - - - private SecureNative(String apiKey, SecureNativeOptions options) throws SecureNativeSDKException { - this.utils = new Utils(); - if (this.utils.isNullOrEmpty(apiKey)) { - throw new SecureNativeSDKException("You must pass your SecureNative api key"); - } - this.apiKey = apiKey; - this.snOptions = initializeOptions(options); - this.eventManager = new SnEventManager(apiKey,this.snOptions); - Logger.setLoggingEnable(this.snOptions.getDebugMode()); - } - - - public static ISDK init(String apiKey, SecureNativeOptions options) throws SecureNativeSDKException { - if (secureNative == null) { - secureNative = new SecureNative(apiKey, options); - if(options != null && options.getDebugMode() != null){ - Logger.setLoggingEnable(options.getDebugMode()); - } - return secureNative; - } - throw new SecureNativeSDKException("This SDK was already initialized"); - } - - public static ISDK getInstance() throws SecureNativeSDKException { - if (secureNative == null) { - throw new SecureNativeSDKException("Secure Native SDK wasnt initialized yet, please call init first"); - } - return secureNative; - } - - private SecureNativeOptions initializeOptions(SecureNativeOptions options) { - if (options == null) { - Logger.getLogger().info("SecureNative options are empty, initializing default values"); - options = new SecureNativeOptions(); - } - if (this.utils.isNullOrEmpty(options.getApiUrl())) { - options.setApiUrl(API_URL); - } - - if (options.getInterval() == 0) { - options.setInterval(INTERVAL); - } - - if (options.getMaxEvents() == 0) { - options.setMaxEvents(MAX_EVENTS); - } - if (options.isAutoSend() == null) { - options.setAutoSend(AUTO_SEND); - } - if (options.getSdkEnabled() == null){ - options.setSdkEnabled(SDK_ENABLED); - } - if (options.getDebugMode() == null){ - options.setSdkEnabled(DEBUG_LOG); - } - if(options.getTimeout() == 0){ - options.setTimeout(DEFAULT_TIMEOUT); - } - if(options.getDebugMode() == null){ - options.setDebugMode(false); - } - - return options; - } - - @Override - public String getDefaultCookieName(){ - return this.utils.COOKIE_NAME; - } - - @Override - public void track(Event event) { - Logger.getLogger().info("Track event call"); - this.eventManager.sendAsync(event, this.snOptions.getApiUrl() + "/track"); - } - - @Override - public RiskResult verify(Event event) { - Logger.getLogger().info("Verify event call"); - return this.eventManager.sendSync(event, this.snOptions.getApiUrl() + "/verify"); - } - - @Override - public RiskResult flow(long flowId, Event event) {//FOR FUTURE PURPOSES - Logger.getLogger().info("Flow event call"); - return this.eventManager.sendSync(event, this.snOptions.getApiUrl() + "/flow/" + flowId); - } - - @Override - public String getApiKey() { - return apiKey; - } - - } \ No newline at end of file diff --git a/sdk-base/src/main/java/com/securenative/snlogic/SnEventManager.java b/sdk-base/src/main/java/com/securenative/snlogic/SnEventManager.java deleted file mode 100644 index 92ffcbc..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/SnEventManager.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.securenative.snlogic; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.securenative.exceptions.SecureNativeSDKException; -import com.securenative.models.*; -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.asynchttpclient.*; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - - -public class SnEventManager implements EventManager { - private final String USER_AGENT_VALUE = "com.securenative.snlogic.SecureNative-java"; - private final String SN_VERSION = "SN-Version"; - private BoundRequestBuilder asyncClient; - private String apiKey; - private Utils utils; - private ExecutorService executor; - private ConcurrentLinkedQueue events; - private ObjectMapper mapper; - private int HTTP_STATUS_OK = 201; - private String AUTHORIZATION = "Authorization"; - private SecureNativeOptions options; - RiskResult defaultRiskResult = new RiskResult(RiskLevel.low.name(), 0.0, new String[0]); - - public SnEventManager(String apiKey, SecureNativeOptions options) throws SecureNativeSDKException { - this.utils = new Utils(); - this.options = options; - events = new ConcurrentLinkedQueue<>(); - if (this.utils.isNullOrEmpty(apiKey) || options == null) { - throw new SecureNativeSDKException("You must pass a valid api key"); - } - this.asyncClient = initializeAsyncHttpClient(options); - this.apiKey = apiKey; - - if (this.options.getSdkEnabled() != null && !this.options.getSdkEnabled()) { - executor = Executors.newSingleThreadScheduledExecutor(); - Logger.getLogger().info(String.format("Starting thread listening to messages queue")); - executor.execute(() -> { - try { - Thread.sleep((long) (Math.random() * 1000)); - Message msg = events.poll(); - if (msg != null) { - sendSync(msg.getSnEvent(), msg.getUrl()); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - }); - } - mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } - - - @Override - public RiskResult sendSync(Event event, String url) { - if (this.options.getSdkEnabled() != null && !this.options.getSdkEnabled()) { - return defaultRiskResult; - } - - this.asyncClient.setHeader(AUTHORIZATION, this.apiKey).setUrl(url); - - try { - this.asyncClient.setBody(mapper.writeValueAsString(event)); - Response response = this.asyncClient.execute().get(); - if (response == null || response.getStatusCode() > HTTP_STATUS_OK) { - Logger.getLogger().info(String.format("Secure Native http call failed to end point: %s with event type %s. adding back to queue.", url, event.getEventType())); - events.add(new Message(event, response.getUri().toUrl())); - } - String responseBody = response.getResponseBody(); - if (utils.isNullOrEmpty(responseBody)) { - Logger.getLogger().info(String.format("Secure Native http call to %s returned with empty response. returning default risk result.", url)); - return defaultRiskResult; - } - Logger.getLogger().info(String.format("Secure Native http call to %s was successful.", url)); - return mapper.readValue(responseBody, RiskResult.class); - } catch (InterruptedException | ExecutionException | IOException e) { - e.printStackTrace(); - } - return defaultRiskResult; - - } - - @Override - public void sendAsync(Event event, String url) { - if (this.options.getSdkEnabled() != null && !this.options.getSdkEnabled()) { - return; - } - this.asyncClient.setUrl(url).setHeader(AUTHORIZATION, this.apiKey); - try { - this.asyncClient.setBody(mapper.writeValueAsString(event)); - } catch (JsonProcessingException e) { - Logger.getLogger().info(String.format("Secure Native async http call failed to end point: %s with event type %s. error: %s", url, event.getEventType(), e)); - } - - this.asyncClient.execute( - new AsyncCompletionHandler() { - @Override - public Object onCompleted(Response response) { - if (response.getStatusCode() > HTTP_STATUS_OK) { - Logger.getLogger().info(String.format("Secure Native http call failed to end point: %s with event type %s. adding back to queue.", url, event.getEventType())); - events.add(new Message(event, response.getUri().toUrl())); - } - return response; - } - }); - - } - - private BoundRequestBuilder initializeAsyncHttpClient(SecureNativeOptions options) { - DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config() - .setConnectTimeout((int) options.getTimeout()) - .setUserAgent(USER_AGENT_VALUE); - AsyncHttpClient client = Dsl.asyncHttpClient(clientBuilder); - Logger.getLogger().info("Initialized Http client"); - return client.preparePost(options.getApiUrl()) - .addHeader(SN_VERSION, this.getVersion()).addHeader("Accept", "application/json"); - - } - - private String getVersion() { - try { - MavenXpp3Reader reader = new MavenXpp3Reader(); - String pomResource = "/META-INF/maven/com.securenative.java/sdk-base/pom.xml"; - Model read = reader.read(new InputStreamReader(SnEventManager.class.getResourceAsStream(pomResource))); - return read.getParent().getVersion(); - } catch (Exception e) { - return "unknown"; - } - } - -} \ No newline at end of file diff --git a/sdk-base/src/main/java/com/securenative/snlogic/Utils.java b/sdk-base/src/main/java/com/securenative/snlogic/Utils.java deleted file mode 100644 index 11e2715..0000000 --- a/sdk-base/src/main/java/com/securenative/snlogic/Utils.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.securenative.snlogic; - -import com.securenative.exceptions.SecureNativeSDKException; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.util.Arrays; -import java.util.Formatter; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class Utils { - private static String[] ipHeaders = {"x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"}; - public String COOKIE_NAME = "_sn"; - public final String SN_HEADER = "x-securenative"; - public final String USERAGENT_HEADER = "user-agent"; - private final String HMAC_SHA1_ALGORITHM = "HmacSHA512"; - private Pattern VALID_IPV6_PATTERN = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}", Pattern.CASE_INSENSITIVE); - private final int AES_KEY_SIZE = 32; - - - public Utils() { - } - - - public String remoteIpFromRequest(Function headerExtractor) { - Logger.getLogger().info("Extracting remote ip from requests"); - Optional bestCandidate = Optional.empty(); - String header = ""; - for (int i = 0; i < ipHeaders.length; i++) { - List candidates = Arrays.asList(); - header = headerExtractor.apply(ipHeaders[i]); - if (!this.isNullOrEmpty(header)) { - candidates = Arrays.stream(header.split(",")).map(s -> s.trim()).filter(s -> !this.isNullOrEmpty(s) && - (isValidInet4Address(s) || this.isIpV6Address(s)) && - !isPrivateIPAddress(s)).collect(Collectors.toList()); - if (candidates.size() > 0) { - Logger.getLogger().info(String.format("Extracted remote ip %s",candidates.get(0))); - return candidates.get(0); - } - } - if (!bestCandidate.isPresent()) { - bestCandidate = candidates.stream().filter(x -> isLoopBack(x)).findFirst(); - } - } - Logger.getLogger().info("couldn't extract remote ip, returning 127.0.0.1"); - return "127.0.0.1"; - } - - - private boolean isLoopBack(String ip) { - try { - return InetAddress.getByName(ip).isLoopbackAddress(); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return false; - } - - private boolean isPrivateIPAddress(String ipAddress) { - InetAddress ia = null; - try { - InetAddress ad = InetAddress.getByName(ipAddress); - byte[] ip = ad.getAddress(); - ia = InetAddress.getByAddress(ip); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return ia.isSiteLocalAddress(); - } - - private String toHexString(byte[] bytes) { - Formatter formatter = new Formatter(); - - for (byte b : bytes) { - formatter.format("%02x", b); - } - - return formatter.toString(); - } - - private String calculateRFC2104HMAC(String data, String key) throws SecureNativeSDKException { - try { - SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM); - Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); - mac.init(signingKey); - return toHexString(mac.doFinal(data.getBytes())); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new SecureNativeSDKException("failed calculating hmac"); - } - } - - private String calculateSignature(String payload, String apikey) { - if (this.isNullOrEmpty(payload)) { - return null; - } - try { - return this.calculateRFC2104HMAC(payload, apikey); - } catch (SecureNativeSDKException e) { - return null; - } - } - - public boolean isVerifiedSnRequest(String payload, String hedaerSignature, String apiKey) { - String signed = calculateSignature(payload, apiKey); - if (this.isNullOrEmpty(signed) || this.isNullOrEmpty(hedaerSignature)) { - return false; - } - return hedaerSignature.equals(signed); - } - - public static boolean isNullOrEmpty(final String s) { - return s == null || s.length() == 0; - } - - private boolean isValidInet4Address(String ip) { - String[] groups = ip.split("\\."); - if (groups.length != 4) - return false; - try { - return Arrays.stream(groups) - .filter(s -> s.length() > 1 && s.startsWith("0")) - .map(Integer::parseInt) - .filter(i -> (i >= 0 && i <= 255)) - .count() == 4; - - } catch (NumberFormatException e) { - return false; - } - } - - private boolean isIpV6Address(String ipAddress) { - return this.VALID_IPV6_PATTERN.matcher(ipAddress).matches(); - } - - public String decrypt(String s, String key) - throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, - IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { - Logger.getLogger().info("Starting to decrypt " + s); - if (s == null || s.length() == 0) { - return s; - } - byte[] cipherText = hexToByteArray(s); - SecretKeySpec skeySpec = new SecretKeySpec(key.substring(0, 32).getBytes("UTF-8"), "AES"); - byte[] ivBytes = Arrays.copyOfRange(cipherText, 0, AES_KEY_SIZE / 2); - cipherText = Arrays.copyOfRange(cipherText, AES_KEY_SIZE / 2, cipherText.length); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - AlgorithmParameterSpec IVspec = new IvParameterSpec(ivBytes); - cipher.init(Cipher.DECRYPT_MODE, skeySpec, IVspec); - return new String(cipher.doFinal(cipherText), "UTF-8").trim(); - } - - private byte[] hexToByteArray(String s) { - byte[] retValue = null; - if (s != null && s.length() != 0) { - retValue = new byte[s.length() / 2]; - for (int i = 0; i < retValue.length; i++) { - retValue[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16); - } - } - return retValue; - } - private final static char[] HEX = new char[]{ - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - - private static String byteArrayToHex(byte[] byteArray) { - StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2); - for (byte b : byteArray) - for (int j = 1; j >= 0; j--) - hexBuffer.append(HEX[(b >> (j * 4)) & 0xF]); - return hexBuffer.toString(); - } - - private byte[] pad (byte[] buf, int size){ - int bufLen = buf.length; - int padLen = size - bufLen%size; - byte[] padded = new byte[bufLen+padLen]; - padded = Arrays.copyOf(buf,bufLen+padLen); - for (int i = 0; i < padLen; i++) { - padded[bufLen+i] = (byte)padLen; - } - return padded; - } - - public static String encrypt(String text, String key) - throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { - SecureRandom secureRandom = new SecureRandom(); - byte[] ivBytes = new byte[16]; - secureRandom.nextBytes(ivBytes); - AlgorithmParameterSpec IVspec = new IvParameterSpec(ivBytes); - SecretKeySpec skeySpec = new SecretKeySpec(key.substring(0, 32).getBytes(StandardCharsets.UTF_8), "AES"); - byte[] source = text.getBytes(StandardCharsets.UTF_8); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, skeySpec, IVspec); - int mod = source.length % 16; - if (mod != 0) { - text = String.format(text + "%" + (16 - mod) + "s", " "); - } - return byteArrayToHex(cipher.doFinal(addAll(ivBytes,text.getBytes("UTF-8")))).trim(); - } - private static byte[] addAll(final byte[] array1, byte[] array2) { - byte[] joinedArray = Arrays.copyOf(array1, array1.length + array2.length); - System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); - return joinedArray; - } -} diff --git a/sdk-base/test/main/java/com/securenative/snlogic/AgentTest.java b/sdk-base/test/main/java/com/securenative/snlogic/AgentTest.java deleted file mode 100644 index 3cb4286..0000000 --- a/sdk-base/test/main/java/com/securenative/snlogic/AgentTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.securenative.snlogic; - -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.IOException; - -import static com.securenative.snlogic.Agent.*; - -public class AgentTest { - - @BeforeClass - public static void setup(){ - - } - - @Test - public void testPomPath(){ - String pomXmlPaths = getPomXmlPaths(); - Assert.assertTrue(pomXmlPaths.equals("debugger-agent-storage.jar")); - System.out.println(pomXmlPaths); - } - - @Test - public void changeClassTest(){ - changeClassMethod(TestClassForByteBuddy.class, TestClassForByteBuddy2.class, "returnOne"); - TestClassForByteBuddy testClassForByteBuddy = new TestClassForByteBuddy(); - Assert.assertTrue(testClassForByteBuddy.returnOne().equals("2")); - } - - @Test - public void test() throws IOException { - Assert.assertTrue(readVersionInfoInManifest().equals("Package name: Apache Log4j API, Package version: 2.11.2")); - } - -} diff --git a/sdk-base/test/main/java/com/securenative/snlogic/SecureNativeTest.java b/sdk-base/test/main/java/com/securenative/snlogic/SecureNativeTest.java deleted file mode 100644 index a566636..0000000 --- a/sdk-base/test/main/java/com/securenative/snlogic/SecureNativeTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.securenative.snlogic; - - -import com.securenative.exceptions.SecureNativeSDKException; -import com.securenative.models.Device; -import com.securenative.models.Event; -import com.securenative.models.EventTypes; -import com.securenative.models.SnEvent; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.Mockito.mock; - -public class SecureNativeTest{ - static Utils utils; - static ISDK sn; - static String API_KEY = "ApiKey"; - - @BeforeClass - public static void runOnceBeforeClass() throws SecureNativeSDKException { - utils = mock(Utils.class); - sn = SecureNative.init(API_KEY, null); - } - - @Test - public void makeSureItsTheSameInstanceTest() throws Exception { - ISDK sn0 = SecureNative.getInstance(); - Assert.assertEquals(sn0.getApiKey(),API_KEY); - } - - @Test - public void TestBasicTrack() throws Exception { - ISDK sn1 = SecureNative.getInstance(); - Event event = new SnEvent.EventBuilder(EventTypes.LOG_OUT.getType()).withCookieValue("ewoJImNpZCI6ICJjaWRWYWx1ZSIsCgkiZnAiOiAidiIKfQ==").withDevice(new Device("id")).withIp("ip").build(); - sn1.track(event); - } - - @Test(expected = SecureNativeSDKException.class) - public void callTrackWith7CustomParams() throws SecureNativeSDKException { - Map params = new HashMap(); - params.put("param_1", "one"); - params.put("param_2", "two"); - params.put("param_3", "three"); - params.put("param_4", "four"); - params.put("param_5", "five"); - params.put("param_6", "six"); - params.put("param_7", "seven"); - new SnEvent.EventBuilder("event").withParams(params).build(); - } - - @Test - public void callTrackWithNullCustomParams() throws SecureNativeSDKException { - Event event = new SnEvent.EventBuilder("event").withParams(null).build(); - Assert.assertEquals(event.getParams().size(),6); - Assert.assertTrue(event.getParams().keySet().contains("param_1")); - Assert.assertTrue(event.getParams().keySet().contains("param_6")); - } - - @Test - public void testDecryption() throws Exception { - String cookie = "821cb59a6647f1edf597956243e564b00c120f8ac1674a153fbd707da0707fb236ea040d1665f3d294aa1943afbae1b26b2b795a127f883ec221c10c881a147bb8acb7e760cd6f04edc21c396ee1f6c9627d9bf1315c484a970ce8930c2ed1011af7e8569325c7edcdf70396f1abca8486eabec24567bf215d2e60382c40e5c42af075379dacdf959cb3fef74f9c9d15"; - String apikey = "6EA4915349C0AAC6F6572DA4F6B00C42DAD33E75"; - Utils utils = new Utils(); - String a = utils.decrypt(cookie,apikey); - String e = "{\"cid\":\"198a41ff-a10f-4cda-a2f3-a9ca80c0703b\",\"fp\":\"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed\"}"; - Assert.assertEquals(e,a); - } - - @Test - public void testEncryptionDecryption() throws Exception { - String apikey = "6EA4915349C0AAC6F6572DA4F6B00C42DAD33E75"; - String e = "{\"cid\":\"198a41ff-a10f-4cda-a2f3-a9ca80c0703b\",\"fp\":\"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed\"}"; - Utils utils = new Utils(); - String a = utils.decrypt(utils.encrypt(e,apikey),apikey); - Assert.assertEquals(e,a); - } -} \ No newline at end of file diff --git a/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy.java b/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy.java deleted file mode 100644 index c3b45a9..0000000 --- a/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.securenative.snlogic; - -public class TestClassForByteBuddy { - public TestClassForByteBuddy() { - } - public String returnOne(){ - return "1"; - } -} - - diff --git a/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy2.java b/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy2.java deleted file mode 100644 index dc5d051..0000000 --- a/sdk-base/test/main/java/com/securenative/snlogic/TestClassForByteBuddy2.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.securenative.snlogic; - -public class TestClassForByteBuddy2 { - public TestClassForByteBuddy2() { - } - public static String returnOne(){ - return "2"; - } -} diff --git a/spring/pom.xml b/spring/pom.xml deleted file mode 100644 index 2f83b87..0000000 --- a/spring/pom.xml +++ /dev/null @@ -1,167 +0,0 @@ - - - - sdk-parent - com.securenative.java - 0.3.0 - - 4.0.0 - spring - - ${project.artifactId} - Secure Native SDK in java - https://github.com/securenative/securenative-java - - - The MIT License - https://opensource.org/licenses/MIT - - - - - Nevo Elmalem - nevo@securenative.com - securenative - http://www.securenative.com - - - - scm:git:git://github.com/securenative/securenative-java.git - scm:git:ssh://github.com:securenative/securenative-java.git - http://github.com/securenative/securenative-java/tree/master - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - maven-assembly-plugin - - - - your.MainClass - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - - - com.securenative.java - sdk-base - 0.2.4 - - - javax.servlet - servlet-api - 2.5 - provided - - - junit - junit - 4.12 - test - - - org.mockito - mockito-core - 2.21.0 - test - - - \ No newline at end of file diff --git a/spring/src/main/java/com/securenative/spring/VerifyRequestMiddleware.java b/spring/src/main/java/com/securenative/spring/VerifyRequestMiddleware.java deleted file mode 100644 index 5edc625..0000000 --- a/spring/src/main/java/com/securenative/spring/VerifyRequestMiddleware.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.securenative.spring; - -import com.securenative.snlogic.ISDK; -import com.securenative.snlogic.SecureNative; -import com.securenative.snlogic.Utils; - -import javax.servlet.*; -import java.io.IOException; - -public class VerifyRequestMiddleware implements Filter { - - private ISDK sn; - - private Utils utils; - - public VerifyRequestMiddleware(SecureNative sn) { - this.sn = sn; - } - - - @Override - public void init(FilterConfig filterConfig){ - utils = new Utils(); - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - - } - - @Override - public void destroy() {} -} diff --git a/spring/src/main/java/com/securenative/spring/VerifyWebHookMiddleware.java b/spring/src/main/java/com/securenative/spring/VerifyWebHookMiddleware.java deleted file mode 100644 index 58de7d3..0000000 --- a/spring/src/main/java/com/securenative/spring/VerifyWebHookMiddleware.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.securenative.spring; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.securenative.models.*; -import com.securenative.snlogic.Logger; -import com.securenative.snlogic.Utils; - -import javax.servlet.*; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Arrays; -import java.util.Optional; - -public class VerifyWebHookMiddleware implements Filter { - private String apikey; - private Utils utils; - private final String EMPTY = ""; - private final String SINATURE_KEY = "x-securenative"; - private ObjectMapper mapper; - - - public VerifyWebHookMiddleware(String apiKey) { - this.apikey = apiKey; - this.utils = new Utils(); - mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - - } - - @Override - public void init(FilterConfig filterConfig) { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest req = (HttpServletRequest) servletRequest; - HttpServletResponse res = (HttpServletResponse) servletResponse; - - String signature = ""; - if (req != null && !this.utils.isNullOrEmpty(req.getHeader(SINATURE_KEY))) { - signature = req.getHeader(SINATURE_KEY); - } - String payload = getBody(servletRequest); - if (utils.isVerifiedSnRequest(payload, signature, this.apikey)) { - filterChain.doFilter(req, res); - return; - } - Logger.getLogger().info("Request have been blocked due to incompatible signature"); - res.sendError(401, "Unauthorized"); - return; - } - - - @Override - public void destroy() { - - } - - private String getBody(ServletRequest servletRequest) throws IOException { - StringBuilder stringBuilder = new StringBuilder(); - BufferedReader bufferedReader = null; - try { - InputStream inputStream = servletRequest.getInputStream(); - if (inputStream != null) { - bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); - char[] charBuffer = new char[128]; - int bytesRead = -1; - while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { - stringBuilder.append(charBuffer, 0, bytesRead); - } - } - } catch (IOException ex) { - throw ex; - } finally { - if (bufferedReader != null) { - try { - bufferedReader.close(); - } catch (IOException ex) { - throw ex; - } - } - } - return stringBuilder.toString(); - } - - public String getCookie(HttpServletRequest request, final String cookieName) { - if (request == null || request.getCookies() == null || request.getCookies().length == 0) { - return null; - } - Optional cookie = Arrays.stream(request.getCookies()).filter(x -> (utils.isNullOrEmpty(cookieName) ? utils.COOKIE_NAME : cookieName).equals(x.getName())).findFirst(); - return cookie.isPresent() ? cookie.get().getValue() : null; - } - - public String remoteIpFromServletRequest(HttpServletRequest request) { - if (request == null) { - return EMPTY; - } - return utils.remoteIpFromRequest(request::getHeader); - } - - public Event buildEventFromHttpServletRequest(HttpServletRequest request, Event event) { - Logger.getLogger().info(String.format("building event from http servlet request")); - String encodedCookie = getCookie(request, event != null && !this.utils.isNullOrEmpty(event.getCookieName()) ? event.getCookieName() : this.utils.COOKIE_NAME); - encodedCookie = utils.isNullOrEmpty(encodedCookie) && !utils.isNullOrEmpty(event.getCookieValue()) ? event.getCookieValue() : encodedCookie; - Logger.getLogger().info("Decoding cookie " + encodedCookie); - String decodedCookie = ""; - ClientFingerPrint clientFingerPrint = new ClientFingerPrint("", ""); - try { - decodedCookie = utils.decrypt(encodedCookie, this.apikey); - clientFingerPrint = mapper.readValue(decodedCookie, ClientFingerPrint.class); - } catch (Exception e) { - Logger.getLogger().info(String.format("Failed decoding cookie %s", encodedCookie)); - } - String eventype = event == null || this.utils.isNullOrEmpty(event.getEventType()) ? EventTypes.LOG_IN.getType() : event.getEventType(); - String ip = event != null && event.getIp() != null ? event.getIp() : remoteIpFromServletRequest(request); - String remoteIP = request.getRemoteAddr(); - String userAgent = event != null && event.getUserAgent() != null ? event.getUserAgent() : request.getHeader(this.utils.USERAGENT_HEADER); - User user = event != null && event.getUser() != null ? event.getUser() : new User(null, null, "anonymous"); - Device device = event != null && event.getDevice() != null ? event.getDevice() : null; - return new SnEvent.EventBuilder(eventype).withCookieValue(this.utils.isNullOrEmpty(decodedCookie) ? request.getHeader(utils.SN_HEADER) : encodedCookie).withIp(ip).withRemoteIP(remoteIP).withUserAgent(userAgent).withUser(user).withDevice(device).withCid(clientFingerPrint.getCid()).withFp(clientFingerPrint.getFp()). - build(); - } - - -} diff --git a/spring/src/test/java/com/securenative/snlogic/VerifyWebHookMiddlewareTest.java b/spring/src/test/java/com/securenative/snlogic/VerifyWebHookMiddlewareTest.java deleted file mode 100644 index 3ad9510..0000000 --- a/spring/src/test/java/com/securenative/snlogic/VerifyWebHookMiddlewareTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.securenative.snlogic; - - -import com.securenative.models.Device; -import com.securenative.models.Event; -import com.securenative.models.EventTypes; -import com.securenative.models.SnEvent; -import com.securenative.spring.VerifyWebHookMiddleware; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; - -import java.io.UnsupportedEncodingException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class VerifyWebHookMiddlewareTest { - - HttpServletRequest request; - Utils utils; - VerifyWebHookMiddleware v; - String key = "6EA4915349C0AAC6F6572DA4F6B00C42DAD33E75"; - String encrypted = "821cb59a6647f1edf597956243e564b00c120f8ac1674a153fbd707da0707fb236ea040d1665f3d294aa1943afbae1b26b2b795a127f883ec221c10c881a147bb8acb7e760cd6f04edc21c396ee1f6c9627d9bf1315c484a970ce8930c2ed1011af7e8569325c7edcdf70396f1abca8486eabec24567bf215d2e60382c40e5c42af075379dacdf959cb3fef74f9c9d15"; - String a = "{\"cid\":\"198a41ff-a10f-4cda-a2f3-a9ca80c0703b\",\"fp\":\"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed\"}"; - - @Before - public void setup() { - v = new VerifyWebHookMiddleware(key); - request = mock(HttpServletRequest.class); - utils = mock(Utils.class); - - } - - @Test - public void buildEventFromHttpServletWhenEventNullTest() throws Exception { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie("_sn",encrypted),new Cookie("n","v")}); - when(request.getHeader("header")).thenReturn("header"); - when(request.getHeader(this.utils.USERAGENT_HEADER)).thenReturn("user_agent_header_test"); - when(request.getRemoteAddr()).thenReturn("address"); - Event event = v.buildEventFromHttpServletRequest(request, null); - Assert.assertEquals(event.getEventType(),"sn.user.login"); - Assert.assertEquals(event.getCid(),"198a41ff-a10f-4cda-a2f3-a9ca80c0703b"); - Assert.assertEquals(event.getFp(),"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed"); - Assert.assertEquals(event.getIp(),"127.0.0.1"); - Assert.assertEquals(event.getRemoteIP(),"address"); - Assert.assertEquals(event.getUserAgent(),"user_agent_header_test"); - Assert.assertEquals(event.getUser().getEmail(),"anonymous"); - Assert.assertEquals(event.getCookieValue(),encrypted); - } - - @Test - public void buildEventFromhttpServletWhenEventValidTest() throws Exception { - when(request.getHeader("header")).thenReturn("header"); - when(request.getHeader(this.utils.USERAGENT_HEADER)).thenReturn("user_agent_header_test"); - when(request.getRemoteAddr()).thenReturn("address"); - Event event = v.buildEventFromHttpServletRequest(request, new SnEvent.EventBuilder(EventTypes.LOG_OUT.getType()).withCookieValue(encrypted).withDevice(new Device("id")).withIp("ip").build()); - Assert.assertEquals(event.getEventType(),"sn.user.logout"); - Assert.assertEquals(event.getCid(),"198a41ff-a10f-4cda-a2f3-a9ca80c0703b"); - Assert.assertEquals(event.getFp(),"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed"); - Assert.assertEquals(event.getIp(),"ip"); - Assert.assertEquals(event.getDevice().getId(),"id"); - Assert.assertEquals(event.getCookieValue(),encrypted); - } - - @Test - public void testEncryptionDecryption() throws NoSuchPaddingException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidAlgorithmParameterException { - Utils utilsEnc = new Utils(); - String enc = utilsEnc.encrypt(a,key); - String dec = utilsEnc.decrypt(enc,key); - Assert.assertEquals(a,dec); - - } -} diff --git a/src/.DS_Store b/src/.DS_Store index 7b0d36729e2ee777a660f9e8c6709dd97bc2fb68..e1029c6f54108470566644d44c7fcd2d11e79194 100644 GIT binary patch delta 106 zcmZoMXfc=|&e%3FQH+&?fq{WzVxkBq6OaJ{OcMjF8JQ;PNC>hplrW?+6f=~h6es5- z<>%*YOblY5Y#_q2nVW-$gRyO6;&}Li5rxq2C delta 76 zcmZoMXfc=|&Zs&uQJ9f&Vvht50|NsS5Q6~Y!~pA!7tGlwUU1#a&LP0TsJijscjn3b aB8r@hKb diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store index c43ee62a22d53cc75b181ee2096e26474c200495..5dfa962e4805ca1c675b24d32b429cb98a2ce8d7 100644 GIT binary patch delta 64 zcmZoMXfc=&$z8;d%8ela!yIGjXH3BqIX@0~=O_0Zf58B G%MSn{qY~Hv diff --git a/src/main/java/com/securenative/ApiManager.java b/src/main/java/com/securenative/ApiManager.java new file mode 100644 index 0000000..d587243 --- /dev/null +++ b/src/main/java/com/securenative/ApiManager.java @@ -0,0 +1,9 @@ +package com.securenative; + +import com.securenative.models.EventOptions; +import com.securenative.models.VerifyResult; + +public interface ApiManager { + void track(EventOptions eventOptions); + VerifyResult verify(EventOptions eventOptions); +} diff --git a/src/main/java/com/securenative/ApiManagerImpl.java b/src/main/java/com/securenative/ApiManagerImpl.java new file mode 100644 index 0000000..577cbb0 --- /dev/null +++ b/src/main/java/com/securenative/ApiManagerImpl.java @@ -0,0 +1,47 @@ +package com.securenative; + +import com.securenative.config.SecureNativeOptions; +import com.securenative.enums.ApiRoute; +import com.securenative.enums.FailoverStrategy; +import com.securenative.enums.RiskLevel; +import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.models.Event; +import com.securenative.models.EventOptions; +import com.securenative.models.VerifyResult; +import com.securenative.models.SDKEvent; + +import java.io.IOException; + +public class ApiManagerImpl implements ApiManager { + private final EventManager eventManager; + private final SecureNativeOptions options; + public static final Logger logger = Logger.getLogger(SecureNative.class); + + public ApiManagerImpl(EventManager eventManager, SecureNativeOptions options) throws SecureNativeSDKException { + this.eventManager = eventManager; + this.options = options; + } + + @Override + public void track(EventOptions eventOptions) { + logger.info("Track event call"); + String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.TRACK.getRoute()); + Event event = new SDKEvent(eventOptions, this.options); + this.eventManager.sendAsync(event,requestUrl, true); + } + + @Override + public VerifyResult verify(EventOptions eventOptions) { + logger.info("Verify event call"); + String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.VERIFY.getRoute()); + Event event = new SDKEvent(eventOptions, this.options); + try { + return this.eventManager.sendSync(VerifyResult.class , event, requestUrl); + } catch (Exception ex) { + logger.error("Failed to call verify", ex); + return this.options.getFailoverStrategy() == FailoverStrategy.FailOpen ? + new VerifyResult(RiskLevel.LOW, 0, new String[0]) + : new VerifyResult(RiskLevel.HIGH, 1, new String[0]); + } + } +} diff --git a/src/main/java/com/securenative/EventManager.java b/src/main/java/com/securenative/EventManager.java new file mode 100644 index 0000000..684c12e --- /dev/null +++ b/src/main/java/com/securenative/EventManager.java @@ -0,0 +1,14 @@ +package com.securenative; + +import com.securenative.exceptions.SecureNativeInvalidUriException; +import com.securenative.exceptions.SecureNativeParseException; +import com.securenative.models.Event; + +import java.io.IOException; + +public interface EventManager { + T sendSync(Class clazz, Event event, String url) throws IOException, SecureNativeParseException; + void sendAsync(Event event, String url, Boolean retry); + void startEventsPersist(); + void stopEventsPersist(); +} diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java new file mode 100644 index 0000000..3e15721 --- /dev/null +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -0,0 +1,61 @@ +package com.securenative; + + +import com.securenative.context.SecureNativeContext; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; +import com.securenative.models.EventOptions; +import com.securenative.enums.EventTypes; +import com.securenative.models.UserTraits; + +import java.util.Date; +import java.util.Map; + +public class EventOptionsBuilder { + private final int MAX_PROPERTIES_SIZE = 10; + private static final Logger logger = Logger.getLogger(EventOptionsBuilder.class); + private final EventOptions eventOptions; + + public static EventOptionsBuilder builder(String eventType){ + return new EventOptionsBuilder(eventType); + } + + public static EventOptionsBuilder builder(EventTypes eventType){ + return new EventOptionsBuilder(eventType.getType()); + } + + private EventOptionsBuilder(String eventType) { + eventOptions = new EventOptions(eventType); + } + + public EventOptionsBuilder userId(String userId) { + this.eventOptions.setUserId(userId); + return this; + } + + public EventOptionsBuilder userTraits(UserTraits userTraits) { + this.eventOptions.setUserTraits(userTraits); + return this; + } + + public EventOptionsBuilder context(SecureNativeContext context) { + this.eventOptions.setContext(context); + return this; + } + + public EventOptionsBuilder properties(Map properties) { + this.eventOptions.setProperties(properties); + return this; + } + + public EventOptionsBuilder timestamp(Date timestamp) { + this.eventOptions.setTimestamp(timestamp); + return this; + } + + public EventOptions build() throws SecureNativeInvalidOptionsException { + if(this.eventOptions.getProperties().size() > MAX_PROPERTIES_SIZE){ + throw new SecureNativeInvalidOptionsException(String.format("You can have only up to %d custom properties", MAX_PROPERTIES_SIZE)); + } + return this.eventOptions; + } +} diff --git a/src/main/java/com/securenative/Logger.java b/src/main/java/com/securenative/Logger.java new file mode 100644 index 0000000..2f06807 --- /dev/null +++ b/src/main/java/com/securenative/Logger.java @@ -0,0 +1,89 @@ +package com.securenative; + +import org.slf4j.LoggerFactory; + +enum LogLevel { + TRACE("trace"), + DEBUG("trace"), + INFO("info"), + WARN("warn"), + ERROR("error"); + + + private final String text; + + LogLevel(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} + +interface ILogger { + void trace(String var1, Object... var2); + void debug(String var1, Object... var2); + void info(String var1, Object... var2); + void warn(String var1, Object... var2); + void error(String var1, Object... var2); +} + +public class Logger implements ILogger { + private static LogLevel _logLevel = LogLevel.ERROR; + private org.slf4j.Logger _logger = null; + + private Logger(Class clazz){ + this._logger = LoggerFactory.getLogger(clazz); + } + + static void initLogger(String logLevel) { + try{ + _logLevel = LogLevel.valueOf(logLevel); + }catch (IllegalArgumentException ex){ + _logLevel = LogLevel.ERROR; + } + } + + public static Logger getLogger(Class clazz) { + return new Logger(clazz); + } + + @Override + public void trace(String var1, Object... var2) { + if(_logLevel == LogLevel.TRACE){ + _logger.error(var1, var2); + } + } + + @Override + public void debug(String var1, Object... var2) { + if(_logLevel == LogLevel.DEBUG){ + _logger.debug(var1, var2); + } + } + + @Override + public void info(String var1, Object... var2) { + if(_logLevel == LogLevel.INFO){ + _logger.error(var1, var2); + } + } + + @Override + public void warn(String var1, Object... var2) { + if(_logLevel == LogLevel.WARN){ + _logger.warn(var1, var2); + } + } + + @Override + public void error(String var1, Object... var2) { + if(_logLevel == LogLevel.ERROR){ + _logger.error(var1, var2); + } + } +} + + diff --git a/src/main/java/com/securenative/Maps.java b/src/main/java/com/securenative/Maps.java new file mode 100644 index 0000000..9005050 --- /dev/null +++ b/src/main/java/com/securenative/Maps.java @@ -0,0 +1,31 @@ +package com.securenative; + +import java.util.HashMap; +import java.util.Map; + +public class Maps { + public static MapWrapper defaultBuilder() { + return new MapWrapper<>(); + } + + public static MapWrapper builder() { + return new MapWrapper(); + } + + public static final class MapWrapper { + private final HashMap map; + + public MapWrapper() { + map = new HashMap(); + } + + public MapWrapper put(K key, V value) { + map.put(key, value); + return this; + } + + public Map build() { + return map; + } + } +} diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java new file mode 100644 index 0000000..c16ed2f --- /dev/null +++ b/src/main/java/com/securenative/SecureNative.java @@ -0,0 +1,93 @@ +package com.securenative; + +import com.securenative.config.ConfigurationManager; +import com.securenative.config.SecureNativeConfigurationBuilder; +import com.securenative.config.SecureNativeOptions; +import com.securenative.context.SecureNativeContextBuilder; +import com.securenative.exceptions.SecureNativeConfigException; +import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.http.SecureNativeHTTPClient; +import com.securenative.models.EventOptions; +import com.securenative.models.VerifyResult; +import com.securenative.utils.SignatureUtils; +import com.securenative.utils.Utils; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.stream.Collectors; + +import static com.securenative.utils.SignatureUtils.SIGNATURE_HEADER; + +public class SecureNative implements ApiManager { + public static final Logger logger = Logger.getLogger(SecureNative.class); + private static SecureNative secureNative = null; + private final ApiManager apiManager; + private final SecureNativeOptions options; + + private SecureNative(SecureNativeOptions options) throws SecureNativeSDKException { + if (Utils.isNullOrEmpty(options.getApiKey())) { + throw new SecureNativeSDKException("You must pass your SecureNative api key"); + } + this.options = options; + this.apiManager = new ApiManagerImpl(new SecureNativeEventManager(new SecureNativeHTTPClient(options), options), options); + Logger.initLogger(options.getLogLevel()); + } + + public static SecureNative init(SecureNativeOptions options) throws SecureNativeSDKException { + if (secureNative == null) { + secureNative = new SecureNative(options); + return secureNative; + } + throw new SecureNativeSDKException("This SDK was already initialized"); + } + + public static SecureNative init(String apiKey) throws SecureNativeSDKException, SecureNativeConfigException { + if (Utils.isNullOrEmpty(apiKey)) { + throw new SecureNativeConfigException("You must pass your SecureNative api key"); + } + SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); + SecureNativeOptions secureNativeOptions = builder.withApiKey(apiKey).build(); + return init(secureNativeOptions); + } + + public static SecureNative init() throws SecureNativeSDKException, SecureNativeConfigException { + SecureNativeOptions secureNativeOptions = ConfigurationManager.loadConfig(); + return init(secureNativeOptions); + } + + public static SecureNative getInstance() throws SecureNativeSDKException { + if (secureNative == null) { + throw new SecureNativeSDKException("Secure Native SDK wasn't initialized yet, please call init first"); + } + return secureNative; + } + + public SecureNativeOptions getOptions() { + return options; + } + + public static SecureNativeConfigurationBuilder configBuilder(){ + return SecureNativeConfigurationBuilder.defaultConfigBuilder(); + } + + public static SecureNativeContextBuilder contextBuilder(){ + return SecureNativeContextBuilder.defaultContextBuilder(); + } + + public boolean verifyRequestPayload(HttpServletRequest request) throws IOException { + String requestSignature = request.getHeader(SIGNATURE_HEADER); + String body = request.getReader().lines().collect(Collectors.joining()); + + return SignatureUtils.isValidSignature(requestSignature, body, this.options.getApiKey()); + } + + @Override + public void track(EventOptions eventOptions) { + this.apiManager.track(eventOptions); + } + + @Override + public VerifyResult verify(EventOptions eventOptions) { + return this.apiManager.verify(eventOptions); + } +} \ No newline at end of file diff --git a/src/main/java/com/securenative/SecureNativeEventManager.java b/src/main/java/com/securenative/SecureNativeEventManager.java new file mode 100644 index 0000000..edfa2a9 --- /dev/null +++ b/src/main/java/com/securenative/SecureNativeEventManager.java @@ -0,0 +1,139 @@ +package com.securenative; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.securenative.exceptions.SecureNativeHttpException; +import com.securenative.exceptions.SecureNativeInvalidUriException; +import com.securenative.exceptions.SecureNativeParseException; +import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.http.HttpClient; +import com.securenative.http.HttpResponse; +import com.securenative.models.Event; +import com.securenative.models.RequestOptions; +import com.securenative.config.SecureNativeOptions; + +import java.io.IOException; +import java.util.concurrent.*; + + +public class SecureNativeEventManager implements EventManager { + private static final Logger logger = Logger.getLogger(SecureNativeEventManager.class); + private final int[] coefficients = new int[] { 1, 1, 2, 3, 5, 8, 13 }; + private int attempt = 0; + private Boolean sendEnabled = false; + private ScheduledExecutorService scheduler; + private final ConcurrentLinkedQueue events; + private final ObjectMapper mapper; + private final SecureNativeOptions options; + private final HttpClient httpClient; + + public SecureNativeEventManager(HttpClient httpClient, SecureNativeOptions options) throws SecureNativeSDKException { + this.options = options; + this.httpClient = httpClient; + + this.events = new ConcurrentLinkedQueue<>(); + mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Override + public T sendSync(Class clazz, Event event, String url) throws IOException, SecureNativeParseException { + if (this.options.getDisabled()) { + logger.warn("SDK is disabled, no operation will be performed"); + return null; + } + + String body = mapper.writeValueAsString(event); + logger.debug("Attempting to send event", body); + HttpResponse response = this.httpClient.post(url, body); + if (!response.isOk()) { + logger.info(String.format("Secure Native http call failed to end point: %s with event type %s. adding back to queue.", url, event.getEventType())); + throw new IOException(String.valueOf(response.getStatusCode())); + } + + String responseBody = response.getBody(); + try { + return mapper.readValue(responseBody, clazz); + }catch (Exception ex){ + logger.error("Failed to parse response body", ex.getMessage()); + throw new SecureNativeParseException(ex.getMessage()); + } + } + + + @Override + public void sendAsync(Event event, String url, Boolean retry) { + if (this.options.getDisabled()) { + return; + } + + try { + String body = mapper.writeValueAsString(event); + this.events.add(new RequestOptions(url, body, retry)); + } catch (JsonProcessingException e) { + logger.error("Failed to deserialize event", e.getMessage()); + } + } + + private void sendEvents() throws InterruptedException { + if (!this.events.isEmpty() && this.sendEnabled) { + RequestOptions requestOptions = events.peek(); + try { + String body = requestOptions.getBody(); + HttpResponse resp = this.httpClient.post(requestOptions.getUrl(), body); + if (resp.getStatusCode() == 401) { + requestOptions.setRetry(false); + } + if (!resp.isOk()) { + throw new SecureNativeHttpException(String.valueOf(resp.getStatusCode())); + } + logger.debug("Event successfully sent", body); + // remove the event from queue + events.remove(requestOptions); + } catch (Exception ex) { + logger.error("Failed to send event", ex.getMessage()); + if (requestOptions.getRetry()) { + if(attempt++ == coefficients.length){ + attempt = 0; + } + int backoff = coefficients[attempt] * this.options.getInterval(); + logger.debug("BackOff automatic sending by", backoff); + this.sendEnabled = false; + Thread.sleep(backoff); + this.sendEnabled = true; + }else{ + // remove the event from queue, retry: false + events.remove(requestOptions); + } + } + } + } + + public void startEventsPersist() { + logger.debug("Starting automatic event persistence"); + if (!this.options.getAutoSend() || this.sendEnabled) { + logger.debug("Automatic event persistence disabled, you should manually persist events"); + return; + } + + this.sendEnabled = true; + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + this.scheduler.scheduleWithFixedDelay(() -> { + try { sendEvents(); } catch (InterruptedException ignored) { } + }, 0, this.options.getInterval(), TimeUnit.MILLISECONDS); + } + + public void stopEventsPersist() { + if (this.sendEnabled) { + logger.debug("Attempting to stop automatic event persistence"); + + try { + this.scheduler.shutdown(); + // drain event queue + this.scheduler.awaitTermination(this.options.getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException ignored) { } + + logger.debug("Stopped event persistence"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java new file mode 100644 index 0000000..245cf7d --- /dev/null +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -0,0 +1,77 @@ +package com.securenative.config; + +import com.securenative.exceptions.SecureNativeConfigException; +import com.securenative.SecureNative; +import com.securenative.utils.Utils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Properties; + +public class ConfigurationManager { + private static final String DEFAULT_CONFIG_FILE = "securenative.properties"; + private static final String CUSTOM_CONFIG_FILE_ENV_NAME = "SECURENATIVE_CONFIG_FILE"; + + private static String getEnvOrDefault(String envName, String defaultValue) { + String envValue = System.getenv(envName); + if (envValue != null) { + return envValue; + } + + String propValue = System.getProperty(envName); + if (propValue != null) { + return propValue; + } + return defaultValue; + } + + private static Properties loadProperties(Properties properties, InputStream inputStream) { + try (final InputStream stream = inputStream) { + properties.load(stream); + } catch (IOException e) { + return new Properties(); + } + return properties; + } + + private static Properties readResourceFile(String resourcePath) { + Properties properties = new Properties(); + URL resourceUrl = SecureNative.class.getClassLoader().getResource(resourcePath); + if (resourceUrl != null) { + InputStream resourceStream = SecureNative.class.getClassLoader().getResourceAsStream(resourcePath); + properties = loadProperties(properties, resourceStream); + } + return properties; + } + + private static String getPropertyOrEnvOrDefault(Properties properties, String key, Object defaultValue){ + String defaultStrValue = defaultValue == null? null: defaultValue.toString(); + Object res = properties.getOrDefault(key, getEnvOrDefault(key, defaultStrValue)); + return res == null? null: res.toString(); + } + + public static SecureNativeConfigurationBuilder configBuilder(){ + return SecureNativeConfigurationBuilder.defaultConfigBuilder(); + } + + public static SecureNativeOptions loadConfig() throws SecureNativeConfigException { + SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); + SecureNativeOptions defaultOptions = builder.build(); + String resourceFilePath = getEnvOrDefault(CUSTOM_CONFIG_FILE_ENV_NAME, DEFAULT_CONFIG_FILE); + Properties properties = readResourceFile(resourceFilePath); + + + builder.withApiKey(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_KEY", defaultOptions.getApiKey())) + .withApiUrl(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_URL", defaultOptions.getApiUrl())) + .withInterval(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_INTERVAL", defaultOptions.getInterval()), defaultOptions.getInterval())) + .withMaxEvents(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_MAX_EVENTS", defaultOptions.getMaxEvents()), defaultOptions.getMaxEvents())) + .withTimeout(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_TIMEOUT", defaultOptions.getTimeout()), defaultOptions.getTimeout())) + .withAutoSend(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_AUTO_SEND", defaultOptions.getAutoSend()), defaultOptions.getAutoSend())) + .withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled())) + .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())); + + return builder.build(); + } +} + diff --git a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java new file mode 100644 index 0000000..c2b8c11 --- /dev/null +++ b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java @@ -0,0 +1,117 @@ +package com.securenative.config; + +import com.securenative.exceptions.SecureNativeConfigException; +import com.securenative.enums.FailoverStrategy; + +public class SecureNativeConfigurationBuilder { + /** + * Api Secret associated with SecureNative account + */ + private String apiKey; + + /** + * SecureNative backend API URL + */ + private String apiUrl; + + /** + * SecureNative event persistence interval + */ + private int interval; + + /** + * Maximum queue capacity + */ + private int maxEvents; + + /** + * Event sending timeout + */ + private int timeout; + + /** + * Allow automatically track event + */ + private Boolean autoSend; + + /** + * Disable SDk, all operation will not take effect + */ + private Boolean disable; + + /** + * Default log level + */ + private String logLevel; + + /** + * Failover strategy + */ + private FailoverStrategy failoverStrategy; + + private SecureNativeConfigurationBuilder(){ } + + public static SecureNativeConfigurationBuilder defaultConfigBuilder() { + return new SecureNativeConfigurationBuilder() + .withApiKey(null) + .withApiUrl("https://api.securenative.com/collector/api/v1") + .withInterval(1000) + .withTimeout(1500) + .withMaxEvents(1000) + .withAutoSend(true) + .withDisable(false) + .withLogLevel("fatal") + .withFailoverStrategy(FailoverStrategy.FailOpen); + } + + public SecureNativeConfigurationBuilder withApiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + public SecureNativeConfigurationBuilder withApiUrl(String apiUrl) { + this.apiUrl = apiUrl; + return this; + } + + public SecureNativeConfigurationBuilder withInterval(int interval) { + this.interval = interval; + return this; + } + + public SecureNativeConfigurationBuilder withMaxEvents(int maxEvents) { + this.maxEvents = maxEvents; + return this; + } + + public SecureNativeConfigurationBuilder withTimeout(int timeout) { + this.timeout = timeout; + return this; + } + + public SecureNativeConfigurationBuilder withAutoSend(Boolean autoSend) { + this.autoSend = autoSend; + return this; + } + + public SecureNativeConfigurationBuilder withDisable(Boolean disable) { + this.disable = disable; + return this; + } + + public SecureNativeConfigurationBuilder withLogLevel(String logLevel) { + this.logLevel = logLevel; + return this; + } + + public SecureNativeConfigurationBuilder withFailoverStrategy(FailoverStrategy failoverStrategy) { + this.failoverStrategy = failoverStrategy; + return this; + } + + + public SecureNativeOptions build() { + return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy); + + } +} diff --git a/src/main/java/com/securenative/config/SecureNativeOptions.java b/src/main/java/com/securenative/config/SecureNativeOptions.java new file mode 100644 index 0000000..6873fbd --- /dev/null +++ b/src/main/java/com/securenative/config/SecureNativeOptions.java @@ -0,0 +1,98 @@ +package com.securenative.config; + +import com.securenative.enums.FailoverStrategy; + +public class SecureNativeOptions { + /** + * Api Secret associated with SecureNative account + */ + private final String apiKey; + + /** + * SecureNative backend API URL + */ + private final String apiUrl; + + /** + * SecureNative event persistence interval + */ + private final int interval; + + /** + * Maximum queue capacity + */ + private final int maxEvents; + + /** + * Event sending timeout + */ + private final int timeout; + + /** + * Allow automatically track event + */ + private final Boolean autoSend; + + /** + * Disable SDk, all operation will not take effect + */ + private final Boolean disable; + + /** + * Default log level + */ + private final String logLevel; + + /** + * Failover strategy + */ + private final FailoverStrategy failoverStrategy; + + public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy) { + this.apiKey = apiKey; + this.apiUrl = apiUrl; + this.interval = interval; + this.maxEvents = maxEvents; + this.timeout = timeout; + this.autoSend = autoSend; + this.disable = disable; + this.logLevel = logLevel; + this.failoverStrategy = failoverStrategy; + } + + public String getApiKey() { + return apiKey; + } + + public String getApiUrl() { + return apiUrl; + } + + public int getInterval() { + return interval; + } + + public int getMaxEvents() { + return maxEvents; + } + + public int getTimeout() { + return timeout; + } + + public Boolean getAutoSend() { + return autoSend; + } + + public Boolean getDisabled() { + return disable; + } + + public String getLogLevel() { + return logLevel; + } + + public FailoverStrategy getFailoverStrategy() { + return failoverStrategy; + } +} diff --git a/src/main/java/com/securenative/context/SecureNativeContext.java b/src/main/java/com/securenative/context/SecureNativeContext.java new file mode 100644 index 0000000..153f918 --- /dev/null +++ b/src/main/java/com/securenative/context/SecureNativeContext.java @@ -0,0 +1,81 @@ +package com.securenative.context; + +import java.util.Map; + +public class SecureNativeContext { + private String clientToken; + private String ip; + private String remoteIp; + private Map headers; + private String url; + private String method; + private String body; + + public SecureNativeContext() { } + + public SecureNativeContext(String clientToken, String ip, String remoteIp, Map headers, String url, String method, String body) { + this.clientToken = clientToken; + this.ip = ip; + this.remoteIp = remoteIp; + this.headers = headers; + this.url = url; + this.method = method; + this.body = body; + } + + public String getClientToken() { + return clientToken; + } + + public void setClientToken(String clientToken) { + this.clientToken = clientToken; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getRemoteIp() { + return remoteIp; + } + + public void setRemoteIp(String remoteIp) { + this.remoteIp = remoteIp; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } +} diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java new file mode 100644 index 0000000..b329bc9 --- /dev/null +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -0,0 +1,77 @@ +package com.securenative.context; + +import com.securenative.utils.RequestUtils; +import com.securenative.utils.Utils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +public class SecureNativeContextBuilder { + private final SecureNativeContext context; + + private SecureNativeContextBuilder() { + this.context = new SecureNativeContext(); + } + + public SecureNativeContextBuilder withClientToken(String clientToken) { + this.context.setClientToken(clientToken); + return this; + } + + public SecureNativeContextBuilder withIp(String ip) { + this.context.setIp(ip); + return this; + } + + public SecureNativeContextBuilder withRemoteIp(String remoteIp) { + this.context.setRemoteIp(remoteIp); + return this; + } + + public SecureNativeContextBuilder withHeaders(Map headers) { + this.context.setHeaders(headers); + return this; + } + + public SecureNativeContextBuilder withUrl(String url) { + this.context.setUrl(url); + return this; + } + + public SecureNativeContextBuilder withMethod(String method) { + this.context.setMethod(method); + return this; + } + + public SecureNativeContextBuilder withBody(String body) { + this.context.setBody(body); + return this; + } + + public static SecureNativeContextBuilder defaultContextBuilder(){ + return new SecureNativeContextBuilder(); + } + + public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) { + Map headers = RequestUtils.getHeadersFromRequest(request); + + String clientToken = RequestUtils.getCookieValueFromRequest(request, RequestUtils.SECURENATIVE_COOKIE); + if(Utils.isNullOrEmpty(clientToken)){ + clientToken = RequestUtils.getSecureHeaderFromRequest(headers); + } + + return new SecureNativeContextBuilder() + .withUrl(request.getRequestURI()) + .withMethod(request.getMethod()) + .withHeaders(headers) + .withClientToken(clientToken) + .withIp(RequestUtils.getClientIpFromRequest(request, headers)) + .withRemoteIp(RequestUtils.getRemoteIpFromRequest(request)) + .withBody(null); + } + + public SecureNativeContext build(){ + return this.context; + } +} + diff --git a/sdk-base/src/main/java/com/securenative/models/ActionType.java b/src/main/java/com/securenative/enums/ActionType.java similarity index 72% rename from sdk-base/src/main/java/com/securenative/models/ActionType.java rename to src/main/java/com/securenative/enums/ActionType.java index 122f564..e9b7aef 100644 --- a/sdk-base/src/main/java/com/securenative/models/ActionType.java +++ b/src/main/java/com/securenative/enums/ActionType.java @@ -1,4 +1,4 @@ -package com.securenative.models; +package com.securenative.enums; public enum ActionType { ALLOW, diff --git a/src/main/java/com/securenative/enums/ApiRoute.java b/src/main/java/com/securenative/enums/ApiRoute.java new file mode 100644 index 0000000..5d91efa --- /dev/null +++ b/src/main/java/com/securenative/enums/ApiRoute.java @@ -0,0 +1,16 @@ +package com.securenative.enums; + +public enum ApiRoute { + TRACK("track"), + VERIFY("verify"); + + private String route; + + public String getRoute() { + return route; + } + + ApiRoute(String route) { + this.route = route; + } +} \ No newline at end of file diff --git a/sdk-base/src/main/java/com/securenative/models/EventTypes.java b/src/main/java/com/securenative/enums/EventTypes.java similarity index 96% rename from sdk-base/src/main/java/com/securenative/models/EventTypes.java rename to src/main/java/com/securenative/enums/EventTypes.java index 8fdec8e..f229736 100644 --- a/sdk-base/src/main/java/com/securenative/models/EventTypes.java +++ b/src/main/java/com/securenative/enums/EventTypes.java @@ -1,4 +1,4 @@ -package com.securenative.models; +package com.securenative.enums; public enum EventTypes { LOG_IN("sn.user.login"), diff --git a/src/main/java/com/securenative/enums/FailoverStrategy.java b/src/main/java/com/securenative/enums/FailoverStrategy.java new file mode 100644 index 0000000..3b44e86 --- /dev/null +++ b/src/main/java/com/securenative/enums/FailoverStrategy.java @@ -0,0 +1,6 @@ +package com.securenative.enums; + +public enum FailoverStrategy { + FailOpen, + FailClosed +} diff --git a/src/main/java/com/securenative/enums/RiskLevel.java b/src/main/java/com/securenative/enums/RiskLevel.java new file mode 100644 index 0000000..0850199 --- /dev/null +++ b/src/main/java/com/securenative/enums/RiskLevel.java @@ -0,0 +1,27 @@ +package com.securenative.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum RiskLevel { + LOW("low"), + MEDIUM("medium"), + HIGH("high"); + + private String riskLevel; + + @JsonValue + public String getRiskLevel() { + return riskLevel; + } + + @JsonCreator + public static RiskLevel fromString(String key) { + return key == null ? null : RiskLevel.valueOf(key.toUpperCase()); + } + + RiskLevel(String riskLevel) { + this.riskLevel = riskLevel; + } + +} \ No newline at end of file diff --git a/src/main/java/com/securenative/exceptions/SecureNativeConfigException.java b/src/main/java/com/securenative/exceptions/SecureNativeConfigException.java new file mode 100644 index 0000000..b6e05ba --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeConfigException.java @@ -0,0 +1,8 @@ +package com.securenative.exceptions; + +public class SecureNativeConfigException extends Exception { + public SecureNativeConfigException(String message) { + super(message); + } +} + diff --git a/src/main/java/com/securenative/exceptions/SecureNativeHttpException.java b/src/main/java/com/securenative/exceptions/SecureNativeHttpException.java new file mode 100644 index 0000000..3bad2fe --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeHttpException.java @@ -0,0 +1,7 @@ +package com.securenative.exceptions; + +public class SecureNativeHttpException extends Exception { + public SecureNativeHttpException(String message) { + super(message); + } +} diff --git a/src/main/java/com/securenative/exceptions/SecureNativeInvalidOptionsException.java b/src/main/java/com/securenative/exceptions/SecureNativeInvalidOptionsException.java new file mode 100644 index 0000000..30a00eb --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeInvalidOptionsException.java @@ -0,0 +1,7 @@ +package com.securenative.exceptions; + +public class SecureNativeInvalidOptionsException extends Exception { + public SecureNativeInvalidOptionsException(String message) { + super(message); + } +} diff --git a/src/main/java/com/securenative/exceptions/SecureNativeInvalidUriException.java b/src/main/java/com/securenative/exceptions/SecureNativeInvalidUriException.java new file mode 100644 index 0000000..931a78c --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeInvalidUriException.java @@ -0,0 +1,8 @@ +package com.securenative.exceptions; + +public class SecureNativeInvalidUriException extends Exception { + public SecureNativeInvalidUriException(String message) { + super(message); + } +} + diff --git a/src/main/java/com/securenative/exceptions/SecureNativeParseException.java b/src/main/java/com/securenative/exceptions/SecureNativeParseException.java new file mode 100644 index 0000000..bfef86c --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeParseException.java @@ -0,0 +1,7 @@ +package com.securenative.exceptions; + +public class SecureNativeParseException extends Exception { + public SecureNativeParseException(String message) { + super(message); + } +} diff --git a/sdk-base/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java b/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java similarity index 98% rename from sdk-base/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java rename to src/main/java/com/securenative/exceptions/SecureNativeSDKException.java index a731873..79c2c4a 100644 --- a/sdk-base/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java +++ b/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java @@ -5,3 +5,6 @@ public SecureNativeSDKException(String message) { super(message); } } + + + diff --git a/src/main/java/com/securenative/http/HttpClient.java b/src/main/java/com/securenative/http/HttpClient.java new file mode 100644 index 0000000..44bfaf8 --- /dev/null +++ b/src/main/java/com/securenative/http/HttpClient.java @@ -0,0 +1,9 @@ +package com.securenative.http; + + +import java.io.IOException; + +public interface HttpClient { + HttpResponse post(String url, String body) throws IOException; +} + diff --git a/src/main/java/com/securenative/http/HttpResponse.java b/src/main/java/com/securenative/http/HttpResponse.java new file mode 100644 index 0000000..c7aed51 --- /dev/null +++ b/src/main/java/com/securenative/http/HttpResponse.java @@ -0,0 +1,23 @@ +package com.securenative.http; + +public class HttpResponse { + private final Boolean ok; + private final int statusCode; + private final String body; + + public HttpResponse(Boolean ok, int statusCode, String body){ + this.ok = ok; + this.statusCode = statusCode; + this.body = body; + } + + public Boolean isOk() { return ok; } + + public int getStatusCode() { + return statusCode; + } + + public String getBody() { + return body; + } +} diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java new file mode 100644 index 0000000..0a09e44 --- /dev/null +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -0,0 +1,51 @@ +package com.securenative.http; + +import com.securenative.config.SecureNativeOptions; +import com.securenative.exceptions.SecureNativeInvalidUriException; +import com.securenative.http.HttpClient; +import com.securenative.http.HttpResponse; +import okhttp3.*; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +public class SecureNativeHTTPClient implements HttpClient { + private final String USER_AGENT_VALUE = "SecureNative-java"; + private final String SN_VERSION = "SN-Version"; + private final OkHttpClient client; + private final SecureNativeOptions options; + public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + + public SecureNativeHTTPClient(SecureNativeOptions options) { + this.options = options; + this.client = new OkHttpClient + .Builder() + .readTimeout(options.getTimeout(), TimeUnit.MILLISECONDS) + .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT)) + .addInterceptor((chain) ->{ + Request request = chain.request(); + Request authenticatedRequest = request.newBuilder() + .header("Authorization", options.getApiKey()).build(); + return chain.proceed(authenticatedRequest); + }).build(); + } + + + @Override + public HttpResponse post(String path, String json) throws IOException { + RequestBody body = RequestBody.create(json, JSON); + + String url = String.format("%s/%s", this.options.getApiUrl(), path); + + Request request = new Request.Builder() + .url(url) + .post(body) + .build(); + try (Response response = this.client.newCall(request).execute()) { + int statusCode = response.code(); + String responseBody = response.body().string(); + return new HttpResponse(response.isSuccessful(), statusCode, responseBody); + } + } +} diff --git a/sdk-base/src/main/java/com/securenative/models/ClientFingerPrint.java b/src/main/java/com/securenative/models/ClientToken.java similarity index 58% rename from sdk-base/src/main/java/com/securenative/models/ClientFingerPrint.java rename to src/main/java/com/securenative/models/ClientToken.java index 932ef22..99dcc45 100644 --- a/sdk-base/src/main/java/com/securenative/models/ClientFingerPrint.java +++ b/src/main/java/com/securenative/models/ClientToken.java @@ -4,14 +4,18 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -public class ClientFingerPrint { +public class ClientToken { private String cid; + private String vid; private String fp; + public ClientToken() { } + @JsonCreator - public ClientFingerPrint(@JsonProperty("cid") String cid, @JsonProperty("fp") String fp) { + public ClientToken(@JsonProperty("cid") String cid, @JsonProperty("vid") String vid, @JsonProperty("fp") String fp) { this.cid = cid; this.fp = fp; + this.vid = vid; } public String getCid() { @@ -22,6 +26,14 @@ public void setCid(String cid) { this.cid = cid; } + public String getVid() { + return vid; + } + + public void setVid(String vid) { + this.vid = vid; + } + public String getFp() { return fp; } diff --git a/sdk-base/src/main/java/com/securenative/models/Device.java b/src/main/java/com/securenative/models/Device.java similarity index 100% rename from sdk-base/src/main/java/com/securenative/models/Device.java rename to src/main/java/com/securenative/models/Device.java diff --git a/src/main/java/com/securenative/models/Event.java b/src/main/java/com/securenative/models/Event.java new file mode 100644 index 0000000..b280c04 --- /dev/null +++ b/src/main/java/com/securenative/models/Event.java @@ -0,0 +1,6 @@ +package com.securenative.models; + +public interface Event { + String getEventType(); + String getTimestamp(); +} diff --git a/src/main/java/com/securenative/models/EventOptions.java b/src/main/java/com/securenative/models/EventOptions.java new file mode 100644 index 0000000..59a36f1 --- /dev/null +++ b/src/main/java/com/securenative/models/EventOptions.java @@ -0,0 +1,63 @@ +package com.securenative.models; + +import com.securenative.context.SecureNativeContext; + +import java.util.Date; +import java.util.Map; + +public class EventOptions { + private String event; + private String userId; + private UserTraits userTraits; + private SecureNativeContext context; + private Map properties; + private Date timestamp; + + public EventOptions(String event) { + this.event = event; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public UserTraits getUserTraits() { + return userTraits; + } + + public void setUserTraits(UserTraits userTraits) { + this.userTraits = userTraits; + } + + public SecureNativeContext getContext() { + return context; + } + + public void setContext(SecureNativeContext context) { + this.context = context; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public Date getTimestamp() { return timestamp; } + + public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } +} diff --git a/src/main/java/com/securenative/models/RequestContext.java b/src/main/java/com/securenative/models/RequestContext.java new file mode 100644 index 0000000..286689c --- /dev/null +++ b/src/main/java/com/securenative/models/RequestContext.java @@ -0,0 +1,116 @@ +package com.securenative.models; + +import java.util.Map; + +public class RequestContext { + private String cid; + private String vid; + private String fp; + private String ip; + private String remoteIp; + private Map headers; + private String url; + private String method; + + public RequestContext() { } + + public RequestContext(String cid, String vid, String fp, String ip, String remoteIp, Map headers, String url, String method) { + this.cid = cid; + this.vid = vid; + this.fp = fp; + this.ip = ip; + this.remoteIp = remoteIp; + this.headers = headers; + this.url = url; + this.method = method; + } + + public String getCid() { + return cid; + } + + public String getVid() { + return vid; + } + + public String getFp() { + return fp; + } + + public String getIp() { + return ip; + } + + public String getRemoteIp() { + return remoteIp; + } + + public Map getHeaders() { + return headers; + } + + public String getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public static class RequestContextBuilder { + private String cid; + private String vid; + private String fp; + private String ip; + private String remoteIp; + private Map headers; + private String url; + private String method; + + public RequestContextBuilder withCid(String cid) { + this.cid = cid; + return this; + } + + public RequestContextBuilder withVid(String vid) { + this.vid = vid; + return this; + } + + public RequestContextBuilder withFp(String fp) { + this.fp = fp; + return this; + } + + public RequestContextBuilder withIp(String ip) { + this.ip = ip; + return this; + } + + public RequestContextBuilder withRemoteIp(String remoteIp) { + this.remoteIp = remoteIp; + return this; + } + + public RequestContextBuilder witHeaders(Map headers) { + this.headers = headers; + return this; + } + + public RequestContextBuilder withUrl(String url) { + this.url = url; + return this; + } + + public RequestContextBuilder withMethod(String method) { + this.method = method; + return this; + } + + public RequestContext build(){ + return new RequestContext(cid, vid, fp, ip, remoteIp, headers, url, method); + } + } + +} + diff --git a/src/main/java/com/securenative/models/RequestOptions.java b/src/main/java/com/securenative/models/RequestOptions.java new file mode 100644 index 0000000..2be7f91 --- /dev/null +++ b/src/main/java/com/securenative/models/RequestOptions.java @@ -0,0 +1,29 @@ +package com.securenative.models; + +public class RequestOptions { + private final String url; + private final String body; + private Boolean retry; + + public RequestOptions(String url, String body, Boolean retry) { + this.url = url; + this.body = body; + this.retry = retry; + } + + public String getUrl() { + return url; + } + + public String getBody() { + return body; + } + + public Boolean getRetry() { + return retry; + } + + public void setRetry(Boolean retry) { + this.retry = retry; + } +} diff --git a/src/main/java/com/securenative/models/SDKEvent.java b/src/main/java/com/securenative/models/SDKEvent.java new file mode 100644 index 0000000..e47484c --- /dev/null +++ b/src/main/java/com/securenative/models/SDKEvent.java @@ -0,0 +1,86 @@ +package com.securenative.models; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.securenative.Logger; +import com.securenative.SecureNative; +import com.securenative.config.SecureNativeOptions; +import com.securenative.context.SecureNativeContext; +import com.securenative.context.SecureNativeContextBuilder; +import com.securenative.utils.DateUtils; +import com.securenative.utils.EncryptionUtils; +import java.util.*; + +public class SDKEvent implements Event { + private final String rid; + public String eventType; + public String userId; + private final UserTraits userTraits; + public RequestContext request; + public String timestamp; + public Map properties; + public static final Logger logger = Logger.getLogger(SecureNative.class); + + public SDKEvent(EventOptions event, SecureNativeOptions options) { + SecureNativeContext context = event.getContext() != null? event.getContext() : SecureNativeContextBuilder.defaultContextBuilder().build(); + + ClientToken clientToken = decryptToken(context.getClientToken(), options.getApiKey()); + + this.rid = UUID.randomUUID().toString(); + this.eventType = event.getEvent(); + this.userId = event.getUserId(); + this.userTraits = event.getUserTraits(); + this.request = new RequestContext.RequestContextBuilder() + .withCid(clientToken.getCid()) + .withVid(clientToken.getVid()) + .withFp(clientToken.getFp()) + .withIp(context.getIp()) + .withRemoteIp(context.getRemoteIp()) + .withMethod(context.getMethod()) + .withUrl(context.getUrl()) + .witHeaders(context.getHeaders()) + .build(); + this.timestamp = DateUtils.toTimestamp(event.getTimestamp()); + this.properties = event.getProperties(); + } + + private ClientToken decryptToken(String token, String key) { + ObjectMapper mapper = new ObjectMapper(); + try { + String decryptedClientToken = EncryptionUtils.decrypt(token, key); + return mapper.readValue(decryptedClientToken, ClientToken.class); + } catch (Exception ex) { + logger.error("Failed to decrypt token"); + } + + return new ClientToken(); + } + + @Override + public String getEventType() { + return this.eventType; + } + + public String getRid() { + return rid; + } + + public String getUserId() { + return userId; + } + + public UserTraits getUserTraits() { + return userTraits; + } + + public RequestContext getRequest() { + return request; + } + + public String getTimestamp() { + return timestamp; + } + + public Map getProperties() { + return properties; + } +} \ No newline at end of file diff --git a/src/main/java/com/securenative/models/UserTraits.java b/src/main/java/com/securenative/models/UserTraits.java new file mode 100644 index 0000000..7e9493d --- /dev/null +++ b/src/main/java/com/securenative/models/UserTraits.java @@ -0,0 +1,49 @@ +package com.securenative.models; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; + +public class UserTraits { + private String name; + private String email; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + private Date createdAt; + + public UserTraits(String name) { + this(name, null, null); + } + public UserTraits(String name, String email) { + this(name, email, null); + } + + public UserTraits(String name, String email, Date createdAt) { + this.name = name; + this.email = email; + this.createdAt = createdAt; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } +} diff --git a/sdk-base/src/main/java/com/securenative/models/RiskResult.java b/src/main/java/com/securenative/models/VerifyResult.java similarity index 59% rename from sdk-base/src/main/java/com/securenative/models/RiskResult.java rename to src/main/java/com/securenative/models/VerifyResult.java index 65e70ae..1ee4acc 100644 --- a/sdk-base/src/main/java/com/securenative/models/RiskResult.java +++ b/src/main/java/com/securenative/models/VerifyResult.java @@ -1,35 +1,36 @@ package com.securenative.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.securenative.enums.RiskLevel; @JsonIgnoreProperties(ignoreUnknown = true) -public class RiskResult { - private String riskLevel; - private double score; +public class VerifyResult { + private RiskLevel riskLevel; + private float score; private String[] triggers; - public RiskResult() { + public VerifyResult() { } - public RiskResult(String riskLevel, double score, String[] triggers) { + public VerifyResult(RiskLevel riskLevel, float score, String[] triggers) { this.riskLevel = riskLevel; this.score = score; this.triggers = triggers; } - public String getRiskLevel() { + public RiskLevel getRiskLevel() { return riskLevel; } - public void setRiskLevel(String riskLevel) { + public void setRiskLevel(RiskLevel riskLevel) { this.riskLevel = riskLevel; } - public double getScore() { + public float getScore() { return score; } - public void setScore(double score) { + public void setScore(float score) { this.score = score; } diff --git a/src/main/java/com/securenative/utils/DateUtils.java b/src/main/java/com/securenative/utils/DateUtils.java new file mode 100644 index 0000000..b33aa1e --- /dev/null +++ b/src/main/java/com/securenative/utils/DateUtils.java @@ -0,0 +1,17 @@ +package com.securenative.utils; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +public class DateUtils { + private static final DateTimeFormatter ISO_8601_PATTERN = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + public static String generateTimestamp() { + return ZonedDateTime.now(ZoneOffset.UTC).format(ISO_8601_PATTERN); + } + + public static String toTimestamp(Date date) { + return ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC).format(ISO_8601_PATTERN); + } +} diff --git a/src/main/java/com/securenative/utils/EncryptionUtils.java b/src/main/java/com/securenative/utils/EncryptionUtils.java new file mode 100644 index 0000000..fb1eaae --- /dev/null +++ b/src/main/java/com/securenative/utils/EncryptionUtils.java @@ -0,0 +1,97 @@ +package com.securenative.utils; + +import com.securenative.Logger; +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + + +public class EncryptionUtils { + private static final String EMPTY_STRING = ""; + private static final Logger logger = Logger.getLogger(EncryptionUtils.class); + private static final int AES_KEY_SIZE = 32; + private final static char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + private static byte[] hexToByteArray(String s) { + byte[] retValue = null; + if (s != null && s.length() != 0) { + retValue = new byte[s.length() / 2]; + for (int i = 0; i < retValue.length; i++) { + retValue[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16); + } + } + return retValue; + } + + private static String byteArrayToHex(byte[] byteArray) { + StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2); + for (byte b : byteArray) + for (int j = 1; j >= 0; j--) + hexBuffer.append(HEX[(b >> (j * 4)) & 0xF]); + return hexBuffer.toString(); + } + + private byte[] pad (byte[] buf, int size){ + int bufLen = buf.length; + int padLen = size - bufLen%size; + byte[] padded = new byte[bufLen+padLen]; + padded = Arrays.copyOf(buf,bufLen+padLen); + for (int i = 0; i < padLen; i++) { + padded[bufLen+i] = (byte)padLen; + } + return padded; + } + + private static byte[] addAll(final byte[] array1, byte[] array2) { + byte[] joinedArray = Arrays.copyOf(array1, array1.length + array2.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + public static String encrypt(String text, String key) { + try { + SecureRandom secureRandom = new SecureRandom(); + byte[] ivBytes = new byte[16]; + secureRandom.nextBytes(ivBytes); + AlgorithmParameterSpec IVspec = new IvParameterSpec(ivBytes); + SecretKeySpec skeySpec = new SecretKeySpec(key.substring(0, AES_KEY_SIZE).getBytes(StandardCharsets.UTF_8), "AES"); + byte[] source = text.getBytes(StandardCharsets.UTF_8); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, IVspec); + int mod = source.length % 16; + if (mod != 0) { + text = String.format(text + "%" + (16 - mod) + "s", " "); + } + return byteArrayToHex(cipher.doFinal(addAll(ivBytes,text.getBytes(StandardCharsets.UTF_8)))).trim(); + } catch (Exception ex) { + logger.error("Unable to encrypt, err:", ex.getMessage()); + } + + return EMPTY_STRING; + } + + public static String decrypt(String s, String key) { + logger.info("Starting to decrypt " + s); + if (s == null || s.length() == 0) { + return s; + } + byte[] cipherText = hexToByteArray(s); + try { + SecretKeySpec skeySpec = new SecretKeySpec(key.substring(0, AES_KEY_SIZE).getBytes("UTF-8"), "AES"); + byte[] ivBytes = Arrays.copyOfRange(cipherText, 0, AES_KEY_SIZE / 2); + cipherText = Arrays.copyOfRange(cipherText, AES_KEY_SIZE / 2, cipherText.length); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + AlgorithmParameterSpec IVspec = new IvParameterSpec(ivBytes); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, IVspec); + return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8).trim(); + } catch (Exception ex) { + logger.error("Unable to decrypt", ex.getMessage()); + } + + return EMPTY_STRING; + } +} diff --git a/src/main/java/com/securenative/utils/IPUtils.java b/src/main/java/com/securenative/utils/IPUtils.java new file mode 100644 index 0000000..72fa47d --- /dev/null +++ b/src/main/java/com/securenative/utils/IPUtils.java @@ -0,0 +1,46 @@ +package com.securenative.utils; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class IPUtils { + private static final Pattern VALID_IPV4_PATTERN = Pattern.compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])", Pattern.CASE_INSENSITIVE); + private static final Pattern VALID_IPV6_PATTERN = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}", Pattern.CASE_INSENSITIVE); + + public static boolean isIpAddress(String ipAddress) { + Matcher m1 = VALID_IPV4_PATTERN.matcher(ipAddress); + if (m1.matches()) { + return true; + } + Matcher m2 = VALID_IPV6_PATTERN.matcher(ipAddress); + return m2.matches(); + } + + public static boolean isValidPublicIp(String ip) { + InetAddress address; + try { + address = InetAddress.getByName(ip); + } catch (UnknownHostException exception) { + return false; + } + + return !(address.isSiteLocalAddress() || + address.isAnyLocalAddress() || + address.isLinkLocalAddress() || + address.isLoopbackAddress() || + address.isMulticastAddress()); + } + + public static boolean isLoopBack(String ip) { + try { + return InetAddress.getByName(ip).isLoopbackAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/com/securenative/utils/RequestUtils.java b/src/main/java/com/securenative/utils/RequestUtils.java new file mode 100644 index 0000000..7608e24 --- /dev/null +++ b/src/main/java/com/securenative/utils/RequestUtils.java @@ -0,0 +1,67 @@ +package com.securenative.utils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +public class RequestUtils { + public final static String SECURENATIVE_COOKIE = "_sn"; + public final static String SECURENATIVE_HEADER = "x-securenative"; + private final static List ipHeaders = Arrays.asList("x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"); + + public static Map getHeadersFromRequest(HttpServletRequest request) { + Map headersMap = new HashMap<>(); + for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { + String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + headersMap.put(headerName, headerValue); + } + return headersMap; + } + + public static String getSecureHeaderFromRequest(Map headers) { + return headers.getOrDefault(SECURENATIVE_HEADER, ""); + } + + public static String getCookieValueFromRequest(HttpServletRequest request, String name) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(name)) { + return cookie.getValue(); + } + } + } + return null; + } + + public static String getClientIpFromRequest(HttpServletRequest request, Map headers) { + Optional bestCandidate = Optional.empty(); + for (String ipHeader: ipHeaders) { + if(!headers.containsKey(ipHeader)){ + continue; + } + String headerValue = headers.get(ipHeader); + + Optional candidateIp = Arrays.stream(headerValue.split(",")) + .map(String::trim) + .filter(IPUtils::isIpAddress) + .filter(IPUtils::isValidPublicIp) + .findFirst(); + + if(candidateIp.isPresent()){ + return candidateIp.get(); + }else if(!bestCandidate.isPresent()) { + bestCandidate = Arrays.stream(headerValue.split(",")) + .map(String::trim) + .filter(IPUtils::isLoopBack) + .findFirst(); + } + } + return bestCandidate.orElseGet(request::getRemoteAddr); + } + + public static String getRemoteIpFromRequest(HttpServletRequest request){ + return request.getRemoteAddr(); + } +} diff --git a/src/main/java/com/securenative/utils/SignatureUtils.java b/src/main/java/com/securenative/utils/SignatureUtils.java new file mode 100644 index 0000000..2963eda --- /dev/null +++ b/src/main/java/com/securenative/utils/SignatureUtils.java @@ -0,0 +1,44 @@ +package com.securenative.utils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Formatter; +import java.util.stream.Collectors; + +import static com.securenative.utils.Utils.timingSafeEqual; + +public class SignatureUtils { + public final static String SIGNATURE_HEADER = "x-securenative"; + private static final String HMAC_SHA512 = "HmacSHA512"; + + private static String toHexString(byte[] bytes) { + Formatter formatter = new Formatter(); + for (byte b : bytes) { + formatter.format("%02x", b); + } + + return formatter.toString(); + } + + private static String buildHmacSignature(String message, String key) { + try { + Mac hasher = Mac.getInstance(HMAC_SHA512); + hasher.init(new SecretKeySpec(key.getBytes(), HMAC_SHA512)); + byte[] hash = hasher.doFinal(message.getBytes()); + return toHexString(hash); + } catch (Exception ignored) { } + + return ""; + } + + public static boolean isValidSignature(String headerSignature, String payload, String apiKey) { + String signed = buildHmacSignature(payload, apiKey); + if (Utils.isNullOrEmpty(signed) || Utils.isNullOrEmpty(headerSignature)) { + return false; + } + + return timingSafeEqual(headerSignature.getBytes(), signed.getBytes()); + } +} diff --git a/src/main/java/com/securenative/utils/Utils.java b/src/main/java/com/securenative/utils/Utils.java new file mode 100644 index 0000000..c453a4f --- /dev/null +++ b/src/main/java/com/securenative/utils/Utils.java @@ -0,0 +1,41 @@ +package com.securenative.utils; + +import com.securenative.Logger; + + + +public class Utils { + private static final Logger logger = Logger.getLogger(Utils.class); + + public static boolean timingSafeEqual(byte[] a, byte[] b) { + if (a.length != b.length) { + return false; + } + + int result = 0; + for (int i = 0; i < a.length; i++) { + result |= a[i] ^ b[i]; + } + return result == 0; + } + + public static Boolean isNullOrEmpty(String str){ + return str == null || str.length() == 0; + } + + public static Integer parseIntegerOrDefault(String str, Integer defaultValue) { + try { + return Integer.valueOf(str); + }catch (NumberFormatException ex){ + return defaultValue; + } + } + + public static Boolean parseBooleanOrDefault(String str, Boolean defaultValue) { + try { + return Boolean.valueOf(str); + }catch (Exception ex){ + return defaultValue; + } + } +} diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java new file mode 100644 index 0000000..617f6d0 --- /dev/null +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -0,0 +1,236 @@ +package com.securenative; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.securenative.config.ConfigurationManager; +import com.securenative.context.SecureNativeContext; +import com.securenative.enums.EventTypes; +import com.securenative.enums.RiskLevel; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; +import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.http.HTTPServerMock; +import com.securenative.models.EventOptions; +import com.securenative.models.UserTraits; +import com.securenative.models.VerifyResult; +import okhttp3.mockwebserver.RecordedRequest; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.util.Date; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ApiManagerImplTest extends HTTPServerMock { + private final EventOptions eventOptions; + + public ApiManagerImplTest() throws SecureNativeInvalidOptionsException { + // init default event for tests + SecureNativeContext context = SecureNative.contextBuilder() + .withIp("127.0.0.1") + .withClientToken("SECURED_CLIENT_TOKEN") + .withHeaders(Maps.defaultBuilder() + .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") + .build()) + .build(); + + eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should call track event") + public void ShouldCallTrackEventTest() throws SecureNativeSDKException, InterruptedException, JSONException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(200); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + try { + // track async event + apiManager.track(eventOptions); + + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + assertThat(body).isNotNull(); + JSONAssert.assertEquals(expected, body, false); + assertThat(new JSONObject(body).has("rid")).isTrue(); + assertThat(new JSONObject(body).has("timestamp")).isTrue(); + } finally { + eventManager.stopEventsPersist(); + } + } + + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should throw when sending more than 10 custom properties to track event") + public void ShouldThrowWhenSendingMoreThan10CustomPropertiesToTrackEventTest() throws SecureNativeSDKException, SecureNativeInvalidOptionsException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(200); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + Map props = IntStream.range(0,11).boxed().collect(Collectors.toMap(i-> String.format("prop%d",i) , i-> String.format("val%d",i))); + + try { + assertThrows(SecureNativeInvalidOptionsException.class, ()->{ + // track async event + apiManager.track(EventOptionsBuilder.builder(EventTypes.LOG_IN) + .properties(props) + .build()); + }); + }finally { + eventManager.stopEventsPersist(); + } + }; + + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should not call track event when automatic persistence disabled") + public void ShouldNotCallTrackEventWhenAutomaticPersistenceDisabledTest() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(500); + eventManager = new SecureNativeEventManager(client, options); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + // track async event + apiManager.track(eventOptions); + + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + + assertThat(lastRequest).isNull(); + assertThat(server.getRequestCount()).isEqualTo(0); + } + + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should not retry unauthorized track event call") + public void ShouldNotRetryUnauthorizedTrackEventCallTest() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(401); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + // track async event + apiManager.track(eventOptions); + + try { + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + + assertThat(lastRequest).isNotNull(); + + // ensure event to be again after backoff + Thread.sleep(10 * options.getInterval()); + + assertThat(server.getRequestCount()).isEqualTo(1); + } finally { + eventManager.stopEventsPersist(); + } + } + + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should call verify event") + public void ShouldCallVerifyEventTest() throws SecureNativeSDKException, JsonProcessingException, InterruptedException, JSONException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + VerifyResult verifyResult = new VerifyResult(RiskLevel.LOW, 0, new String[0]); + String body = new ObjectMapper().writeValueAsString(verifyResult); + + client = sandbox().mock(200, body); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + + // call verify event + VerifyResult result = apiManager.verify(eventOptions); + + assertThat(result.getRiskLevel()).isEqualTo(verifyResult.getRiskLevel()); + assertThat(result.getScore()).isEqualTo(verifyResult.getScore()); + assertThat(result.getTriggers().length).isEqualTo(verifyResult.getTriggers().length); + + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String lastRequestBody = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + assertThat(lastRequestBody).isNotNull(); + JSONAssert.assertEquals(expected, lastRequestBody, false); + assertThat(new JSONObject(lastRequestBody).has("rid")).isTrue(); + assertThat(new JSONObject(lastRequestBody).has("timestamp")).isTrue(); + } + + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should fail verify event call when unauthorized") + public void ShouldFailVerifyEventCallWhenUnauthorizedTest() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + client = sandbox().mock(401); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + ApiManager apiManager = new ApiManagerImpl(eventManager, options); + + // call verify event + VerifyResult verifyResult = apiManager.verify(eventOptions); + assertThat(verifyResult.getRiskLevel()).isEqualTo(RiskLevel.LOW); + assertThat(verifyResult.getScore()).isEqualTo(0); + assertThat(verifyResult.getTriggers().length).isEqualTo(0); + + assertThat(verifyResult).isNotNull(); + + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String lastRequestBody = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + assertThat(lastRequestBody).isNotNull(); + + } +} diff --git a/src/test/java/com/securenative/EventManagerTest.java b/src/test/java/com/securenative/EventManagerTest.java new file mode 100644 index 0000000..45309dd --- /dev/null +++ b/src/test/java/com/securenative/EventManagerTest.java @@ -0,0 +1,291 @@ +package com.securenative; + +import com.fasterxml.jackson.databind.JsonNode; +import com.securenative.config.ConfigurationManager; +import com.securenative.exceptions.SecureNativeParseException; +import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.http.HTTPServerMock; +import com.securenative.models.Event; +import com.securenative.models.SampleEvent; +import okhttp3.mockwebserver.RecordedRequest; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EventManagerTest extends HTTPServerMock { + private final Event event = new SampleEvent(); + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should successfully send async event with status code 200") + public void SendAsyncEventWithStatusCode200Test() throws SecureNativeSDKException, InterruptedException, JSONException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(200); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + + eventManager.sendAsync( event, "some-path/to-api",true); + + try{ + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + String expected = "{\"eventType\":\"custom-event\"}"; + + JSONAssert.assertEquals(expected, body, false); + assertThat(new JSONObject(body).has("timestamp")).isTrue(); + }finally { + eventManager.stopEventsPersist(); + } + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should handle async event invalid json response with status 200") + public void ShouldHandleInvalidJsonResponseWithStatus200Test() throws InterruptedException, JSONException, SecureNativeSDKException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(200, "bla bla"); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + + try { + // track async event + eventManager.sendAsync(event, "some-path/to-api", true); + + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + + assertThat(body).isNotNull(); + //timestamp + assertThat(new JSONObject(body).has("timestamp")).isTrue(); + //event type + assertThat(new JSONObject(body).get("eventType")).isEqualTo(event.getEventType()); + } finally { + eventManager.stopEventsPersist(); + } + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should not retry sending async event when status code 200") + public void ShouldNotRetrySendingAsyncEventWhenStatusCode200Test() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + + client = sandbox().mock(200); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + + try { + // track async event + eventManager.sendAsync(event, "some-path/to-api", true); + + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + + // first attempt should be called + assertThat(lastRequest).isNotNull(); + + // let's give option to send again + Thread.sleep(2 * options.getInterval()); + + // should be called only once + assertThat(server.getRequestCount()).isEqualTo(1); + } finally { + eventManager.stopEventsPersist(); + } + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should not retry sending async event when status code 401") + public void ShouldNotRetrySendingAsyncEventWhenStatusCode401Test() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + + client = sandbox().mock(401); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + + try { + // track async event + eventManager.sendAsync(event, "some-path/to-api", true); + + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + + + assertThat(lastRequest).isNotNull(); + + // let give client time to retry + Thread.sleep(10 * options.getInterval()); + + // should be called only once + assertThat(server.getRequestCount()).isEqualTo(1); + } finally { + eventManager.stopEventsPersist(); + } + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should retry sending async event when status code 500") + public void ShouldRetrySendingAsyncEventWhenStatusCode500Test() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); + + client = sandbox().mock(500); + eventManager = new SecureNativeEventManager(client, options); + eventManager.startEventsPersist(); + + try { + // track async event + eventManager.sendAsync(event, "some-path/to-api", true); + + // ensure event to be sent + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + + assertThat(lastRequest).isNotNull(); + + //set mock to successful attempt + mock(200); + + Thread.sleep(20 * options.getInterval()); + assertThat(server.getRequestCount()).isEqualTo(2); + } finally { + eventManager.stopEventsPersist(); + } + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should successfully send sync event with status code 200") + public void ShouldSuccessfullySendSyncEventWithStatusCode200Test() throws SecureNativeSDKException, JSONException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + String resBody = "{ \"data\": true }"; + client = sandbox().mock(200, resBody); + eventManager = new SecureNativeEventManager(client, options); + + // track async event + JsonNode data = null; + try { + data = eventManager.sendSync(JsonNode.class, event, "some-path/to-api"); + } catch (Exception ignored) { } + + JSONAssert.assertEquals(resBody, data.toString(), false); + + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; + String expected = "{\"eventType\":\"custom-event\"}"; + + JSONAssert.assertEquals(expected, body, false); + assertThat(new JSONObject(body).has("timestamp")).isTrue(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should send sync event and handle invalid json response") + public void ShouldSendSyncEventAndHandleInvalidJsonResponseTest() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + client = sandbox().mock(200, "bla bla"); + eventManager = new SecureNativeEventManager(client, options); + + + // track async event + String resp = null; + try { + resp = eventManager.sendSync(String.class, event, "some-path/to-api"); + } catch (Exception ignored) { } + + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + //invalid json response will turn into null + assertThat(resp).isNull(); + assertThat(lastRequest).isNotNull(); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should send sync event and handle invalid request url") + public void ShouldSendSyncEventAndHandleInvalidRequestUrlTest() throws SecureNativeSDKException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + client = sandbox().mock(500); + eventManager = new SecureNativeEventManager(client, options); + + try { + Object obj = eventManager.sendSync(Object.class, event, "path what"); + assertThat(obj).isNull(); + } catch (Exception ignored) { + + } + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should send sync event and fail when status code 401") + public void ShouldSendSyncEventAndFailWhenStatusCode401Test() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + + client = sandbox().mock(401); + eventManager = new SecureNativeEventManager(client, options); + + try { + // track async event + eventManager.sendSync(Object.class, event, "some-path/to-api"); + } catch (SecureNativeParseException | IOException ex) { + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + assertThat(lastRequest).isNotNull(); + assertThat(ex.getMessage()).contains("401"); + } + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should send sync event and fail when status code 500") + public void ShouldSendSyncEventAndFailWhenStatusCode500Test() throws SecureNativeSDKException, InterruptedException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + client = sandbox().mock(500); + eventManager = new SecureNativeEventManager(client, options); + + try { + // track async event + eventManager.sendSync(Object.class, event, "some-path/to-api"); + } catch (Exception ex) { + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + assertThat(lastRequest).isNotNull(); + assertThat(ex.getMessage()).contains("500"); + } + } +} diff --git a/src/test/java/com/securenative/SecureNativeTest.java b/src/test/java/com/securenative/SecureNativeTest.java new file mode 100644 index 0000000..650d34c --- /dev/null +++ b/src/test/java/com/securenative/SecureNativeTest.java @@ -0,0 +1,135 @@ +package com.securenative; + +import com.securenative.config.SecureNativeOptions; +import com.securenative.enums.FailoverStrategy; +import com.securenative.exceptions.SecureNativeConfigException; +import com.securenative.exceptions.SecureNativeSDKException; +import org.junit.jupiter.api.*; +import org.junitpioneer.jupiter.SetSystemProperty; + +import java.lang.reflect.Field; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class SecureNativeTest{ + @AfterEach + public void cleanUp() throws NoSuchFieldException, IllegalAccessException { + Field instance = SecureNative.class.getDeclaredField("secureNative"); + instance.setAccessible(true); + instance.set(null, null); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(1) + @DisplayName("Should init SDK with all public methods defined") + public void initSDKWithPublicMethodsDefinedTest() { + assertThat(SecureNative.class).hasDeclaredMethods("track", "verify"); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(2) + @DisplayName("Should throw when getting SDK instance without init") + public void getSDKInstanceWithoutInitThrowsTest() { + assertThrows(SecureNativeSDKException.class, SecureNative::getInstance); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @SetSystemProperty(key = "SECURENATIVE_CONFIG_FILE", value = "FILE_THAT_MISSING") + @Order(3) + @DisplayName("Should throw when try init sdk without api key") + public void initSDKWithoutApiKeyShouldThrowTest() throws SecureNativeConfigException, SecureNativeSDKException { + assertThrows(SecureNativeSDKException.class, ()->{ + SecureNative secureNative = SecureNative.init(); + }); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(4) + @DisplayName("Should throw when try init sdk with empty api key") + public void initSDKWithEmptyApiKeyShouldThrowTest() { + assertThrows(SecureNativeConfigException.class, ()->{ + SecureNative.init(""); + }); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(5) + @DisplayName("Should init SDK with API key and default options") + public void initSDKWithApiKeyAndDefaultsTest() throws SecureNativeConfigException, SecureNativeSDKException { + final String apiKey = "API_KEY"; + SecureNative secureNative = SecureNative.init(apiKey); + SecureNativeOptions options = secureNative.getOptions(); + + assertThat(options.getApiKey()).isEqualTo(apiKey); + assertThat(options.getApiUrl()).isEqualTo("https://api.securenative.com/collector/api/v1"); + assertThat(options.getInterval()).isEqualTo(1000); + assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getMaxEvents()).isEqualTo(1000); + assertThat(options.getAutoSend()).isEqualTo(true); + assertThat(options.getAutoSend()).isEqualTo(true); + assertThat(options.getDisabled()).isEqualTo(false); + assertThat(options.getLogLevel()).isEqualTo("fatal"); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FailOpen); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(6) + @DisplayName("Should throw exception when SDK initialized twice") + public void initSDKTwiceWillThrowTest(){ + assertThrows(SecureNativeSDKException.class, ()->{ + SecureNative.init(); + SecureNative.init(); + }); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(7) + @DisplayName("Initialized SDK instance should match singleton") + public void initSDKWithApiKeyAndGetInstanceShouldMatchTest() throws SecureNativeConfigException, SecureNativeSDKException { + final String apiKey = "API_KEY"; + SecureNative secureNative = SecureNative.init(apiKey); + + assertThat(secureNative).isEqualTo(SecureNative.getInstance()); + assertThat(secureNative).isEqualTo(SecureNative.getInstance()); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(8) + @DisplayName("Should init SDK with builder correctly") + public void initSDKWithBuilderTest() throws SecureNativeConfigException, SecureNativeSDKException { + SecureNative secureNative = SecureNative.init(SecureNative.configBuilder() + .withApiKey("API_KEY") + .withMaxEvents(10) + .withLogLevel("error") + .build()); + + SecureNativeOptions options = secureNative.getOptions(); + + assertThat(options).extracting("apiKey", "maxEvents", "logLevel") + .containsExactly("API_KEY", 10, "error"); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Order(9) + @DisplayName("Should init SDK with property file correctly") + public void initSDKAndLoadFromPropertiesFileTest() throws SecureNativeConfigException, SecureNativeSDKException { + SecureNative secureNative = SecureNative.init(); + SecureNativeOptions options = secureNative.getOptions(); + + assertThat(options).extracting("apiKey", "timeout") + .containsExactly("SOME_API_KEY", 2000); + } +} diff --git a/src/test/java/com/securenative/http/HTTPServerMock.java b/src/test/java/com/securenative/http/HTTPServerMock.java new file mode 100644 index 0000000..a74ff10 --- /dev/null +++ b/src/test/java/com/securenative/http/HTTPServerMock.java @@ -0,0 +1,63 @@ +package com.securenative.http; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.securenative.EventManager; +import com.securenative.config.SecureNativeConfigurationBuilder; +import com.securenative.config.SecureNativeOptions; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; + +import java.io.IOException; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public abstract class HTTPServerMock { + private HttpUrl serverUrl; + protected SecureNativeConfigurationBuilder configBuilder; + protected MockWebServer server; + protected SecureNativeOptions options; + protected HttpClient client; + protected EventManager eventManager; + protected final ObjectMapper mapper = new ObjectMapper(); + + @BeforeEach + protected void start() throws IOException { + server = new MockWebServer(); + server.start(); + serverUrl = server.url("/api"); + } + + @AfterEach + protected void shutdown() throws Exception { + server.shutdown(); + } + + public HttpClient mock(int code){ + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(code); + server.enqueue(mockResponse); + + return this.client; + } + + public HttpClient mock(int code, String body){ + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(code); + mockResponse.setBody(body); + server.enqueue(mockResponse); + + return this.client; + } + + protected HTTPServerMock sandbox(){ + this.options = configBuilder.withApiUrl(serverUrl.toString()) + .build(); + + this.client = new SecureNativeHTTPClient(options); + + return this; + } +} diff --git a/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java new file mode 100644 index 0000000..4a5e2cb --- /dev/null +++ b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java @@ -0,0 +1,31 @@ +package com.securenative.http; +import com.securenative.config.ConfigurationManager; +import com.securenative.exceptions.SecureNativeInvalidUriException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SecureNativeHTTPClientTest extends HTTPServerMock { + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should make simple http post call") + public void shouldMakeSimplePostCallTest() throws IOException, SecureNativeInvalidUriException { + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); + + client = sandbox().mock(200, "SOME_BODY"); + + String payload = "{\"event\":\"SOME_EVENT_NAME\"}"; + + HttpResponse response = client.post("track", payload); + + assertThat(response.isOk()).isEqualTo(true); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.getBody()).isEqualTo("SOME_BODY"); + } +} diff --git a/src/test/java/com/securenative/models/SampleEvent.java b/src/test/java/com/securenative/models/SampleEvent.java new file mode 100644 index 0000000..a28ea88 --- /dev/null +++ b/src/test/java/com/securenative/models/SampleEvent.java @@ -0,0 +1,18 @@ +package com.securenative.models; + +import com.securenative.utils.DateUtils; + +public class SampleEvent implements Event { + private final String eventType = "custom-event"; + private final String timestamp = DateUtils.generateTimestamp(); + + @Override + public String getEventType() { + return eventType; + } + + @Override + public String getTimestamp() { + return timestamp; + } +} diff --git a/src/test/java/com/securenative/utils/DateUtilsTest.java b/src/test/java/com/securenative/utils/DateUtilsTest.java new file mode 100644 index 0000000..ce96d4c --- /dev/null +++ b/src/test/java/com/securenative/utils/DateUtilsTest.java @@ -0,0 +1,31 @@ +package com.securenative.utils; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.time.Instant; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +public class DateUtilsTest { + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should convert date to iso8601 format") + public void toTimestampTest() { + String iso8601Date = "2000-01-01T00:00:00.000Z"; + Date date = Date.from(Instant.parse(iso8601Date)); + String result = DateUtils.toTimestamp(date); + + Assertions.assertThat(result).isEqualTo(iso8601Date); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should generate current date in iso8601 format") + public void generateTimestampTest() { + String result = DateUtils.generateTimestamp(); + Assertions.assertThat(result).isNotEmpty(); + } +} diff --git a/src/test/java/com/securenative/utils/EncryptionUtilsTest.java b/src/test/java/com/securenative/utils/EncryptionUtilsTest.java new file mode 100644 index 0000000..9365994 --- /dev/null +++ b/src/test/java/com/securenative/utils/EncryptionUtilsTest.java @@ -0,0 +1,74 @@ +package com.securenative.utils; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.concurrent.TimeUnit; + +public class EncryptionUtilsTest { + private final String SECRET_KEY = "B00C42DAD33EAC6F6572DA756EA4915349C0A4F6"; + private final String PAYLOAD = "{\"cid\":\"198a41ff-a10f-4cda-a2f3-a9ca80c0703b\",\"vi\":\"148a42ff-b40f-4cda-a2f3-a8ca80c0703b\",\"fp\":\"6d8cabd95987f8318b1fe01593d5c2a5.24700f9f1986800ab4fcc880530dd0ed\"}"; + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should encrypt message correctly") + public void encryptTest() { + String result = EncryptionUtils.encrypt(PAYLOAD, SECRET_KEY); + Assertions.assertThat(result).isNotEmpty(); + Assertions.assertThat(result).hasSizeGreaterThan(PAYLOAD.length()); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should decrypt message correctly") + public void decryptTest(){ + String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; + String result = EncryptionUtils.decrypt(encryptedPayload, SECRET_KEY); + Assertions.assertThat(result).isEqualTo(PAYLOAD); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should encrypt and decrypt message correctly") + public void encryptDecryptTest(){ + String encRes = EncryptionUtils.encrypt(PAYLOAD, SECRET_KEY); + String decRes = EncryptionUtils.decrypt(encRes, SECRET_KEY); + Assertions.assertThat(decRes).isEqualTo(PAYLOAD); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should handle encryption with short key") + public void encryptWithInvalidKeyLenTest(){ + String secretKey = "BAD_KEY"; + String result = EncryptionUtils.encrypt(PAYLOAD, secretKey); + Assertions.assertThat(result).hasSize(0); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should handle decryption with short key") + public void decryptWithInvalidKeyLenTest(){ + String secretKey = "BAD_KEY"; + String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; + + String result = EncryptionUtils.decrypt(encryptedPayload, secretKey); + + Assertions.assertThat(result).hasSize(0); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should decrypt with key which is too long") + public void encryptDecryptWithKeyWhichTooLongTest(){ + String secretKey = "B00C42DAD33EAC6F6572DA756EA4915349C0A4F6B00C42DAD33EAC6F6572DA756EA4915349C0A4F6"; + + String encRes = EncryptionUtils.encrypt(PAYLOAD, secretKey); + String decRes = EncryptionUtils.decrypt(encRes, secretKey); + + Assertions.assertThat(decRes).isEqualTo(PAYLOAD); + } + +} diff --git a/src/test/java/com/securenative/utils/IPUtilsTest.java b/src/test/java/com/securenative/utils/IPUtilsTest.java new file mode 100644 index 0000000..2a41a71 --- /dev/null +++ b/src/test/java/com/securenative/utils/IPUtilsTest.java @@ -0,0 +1,67 @@ +package com.securenative.utils; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.concurrent.TimeUnit; + +public class IPUtilsTest { + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is valid ipv4") + public void isIpAddressValidIpV4Test() { + String validIPv4 = "172.16.254.1"; + Assertions.assertThat(IPUtils.isIpAddress(validIPv4)).isTrue(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is valid ipv6") + public void isIpAddressValidIpV6Test() { + String validIPv6 = "2001:db8:1234:0000:0000:0000:0000:0000"; + Assertions.assertThat(IPUtils.isIpAddress(validIPv6)).isTrue(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is invalid ipv4") + public void isIpAddressInvalidIpV4Test() { + String validIPv4 = "172.16.2541"; + Assertions.assertThat(IPUtils.isIpAddress(validIPv4)).isFalse(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is invalid ipv6") + public void isIpAddressInvalidIpV6Test() { + String validIPv6 = "2001:db8:1234:0000"; + Assertions.assertThat(IPUtils.isIpAddress(validIPv6)).isFalse(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is valid public ip") + public void isValidPublicIpTest() { + String ip = "64.71.222.37"; + Assertions.assertThat(IPUtils.isValidPublicIp(ip)).isTrue(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is not valid public ip") + public void isNotValidPublicIpTest() { + String ip = "10.0.0.0"; + Assertions.assertThat(IPUtils.isValidPublicIp(ip)).isFalse(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Check if ip is valid loopback ip") + public void isValidLoopbackIpTest() { + String ip = "127.0.0.1"; + Assertions.assertThat(IPUtils.isLoopBack(ip)).isTrue(); + } +} + diff --git a/src/test/java/com/securenative/utils/SignatureUtilsTest.java b/src/test/java/com/securenative/utils/SignatureUtilsTest.java new file mode 100644 index 0000000..e0dc464 --- /dev/null +++ b/src/test/java/com/securenative/utils/SignatureUtilsTest.java @@ -0,0 +1,30 @@ +package com.securenative.utils; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.concurrent.TimeUnit; + +public class SignatureUtilsTest { + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Verify request signature") + public void verifyRequestPayloadTest() { + String signature = "c4574c1748064735513697750c6223ff36b03ae3b85b160ce8788557d01e1d9d1c9cd942074323ee0061d3dcc8c94359c5acfa6eee8e2da095b3967b1a88ab73"; + String payload = "{\"id\":\"4a9157ffbd18cfbd73a57298\",\"type\":\"security-action\",\"flow\":{\"id\":\"62298c73a9bb433fbd1f75984a9157fd\",\"name\":\"Block user that violates geo velocity\"},\"userId\":\"73a9bb433fbd1f75984a9157\",\"userTraits\":{\"name\":\"John Doe\",\"email\":\"john.doe@gmail.com\"},\"request\":{\"ip\":\"10.0.0.0\",\"fp\":\"9bb433fb984a9157d1f7598\"},\"action\":\"block\",\"properties\":{\"type\":\"customer\"},\"timestamp\":\"2020-02-23T22:28:55.387Z\"}"; + String secretKey = "B00C42DAD33EAC6F6572DA756EA4915349C0A4F6"; + + Boolean result = SignatureUtils.isValidSignature(signature, payload, secretKey); + Assertions.assertThat(result).isTrue(); + } + + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Verify request with empty signature") + public void verifyRequestEmptySignatureTest() { + Boolean result = SignatureUtils.isValidSignature("", "", "B00C42DAD33EAC6F6572DA756EA4915349C0A4F6"); + Assertions.assertThat(result).isFalse(); + } +} diff --git a/src/test/resources/securenative.properties b/src/test/resources/securenative.properties new file mode 100644 index 0000000..53a61e1 --- /dev/null +++ b/src/test/resources/securenative.properties @@ -0,0 +1,2 @@ +SECURENATIVE_API_KEY=SOME_API_KEY +SECURENATIVE_TIMEOUT=2000 \ No newline at end of file From d8c3738eee067d2b7af43fd46a06936777204e54 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 3 May 2020 20:04:59 +0300 Subject: [PATCH 02/82] Updated jackson dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db5238f..b37cf81 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ com.fasterxml.jackson.core jackson-databind - 2.9.9.2 + 2.11.0 javax.servlet From a664eef42d41c847b205c3cf4a89a877c0c6ef17 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 3 May 2020 20:23:34 +0300 Subject: [PATCH 03/82] Updated readme --- README.md | 179 +++++++++++++++++++++++------------------------------- 1 file changed, 76 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index a65e6c9..3bae60c 100644 --- a/README.md +++ b/README.md @@ -56,125 +56,98 @@ SecureNative secureNative = SecureNative.getInstance(); ## Tracking events -Once the SDK has been initialized, tracking requests are sent through the SDK +Once the SDK has been initialized, tracking requests sent through the SDK instance. Make sure you build event with the EventBuilder: ```java -Event event = new SnEvent.EventBuilder(EventTypes.LOG_IN.getType()). - withUser(new User("","","apple@sucks.com")). - withIp("35.199.23.1"). - withCookieValue("eyJjaWQiOiJkYzgyYjdhZS00ODFkLTQyODItYTMyZC0xZTU1Njk2ZjNmZTQiLCJmcCI6Ijk5NGYzZjVjZTRiYWUwODQzMTRhOTFkNzgyN2I1MWYuMjQ3MDBmOWYxOTg2ODAwYWI0ZmNjODgwNTMwZGQwZWQifQ"). - withRemoteIP("35.199.23.1"). - withUserAgent("Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; GT-I9500 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.0 QQ-URL-Manager Mobile Safari/537.36"). - build(); - ``` - -**Example** - -```java - @RequestMapping("/track") - public String track( HttpServletRequest request, HttpServletResponse response) { - try { - secureNative = new SecureNative(API_KEY,new SecureNativeOptions()); - Event event = new SnEvent.EventBuilder(EventTypes.LOG_IN.getType()). - withUser(new User("","","chuck@norris.com")). - withIp("35.199.23.1"). - withCookieValue("eyJjaWQiOiJkYzgyYjdhZS00ODFkLTQyODItYTMyZC0xZTU1Njk2ZjNmZTQiLCJmcCI6Ijk5NGYzZjVjZTRiYWUwODQzMTRhOTFkNzgyN2I1MWYuMjQ3MDBmOWYxOTg2ODAwYWI0ZmNjODgwNTMwZGQwZWQifQ"). - withRemoteIP("35.199.23.1"). - withUserAgent("Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; GT-I9500 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.0 QQ-URL-Manager Mobile Safari/537.36"). - build(); - secureNative.track(event); - - - } catch (SecureNativeSDKException e) { - e.printStackTrace(); - return "Api key is not valid"; - } - return "tracked"; - } - -``` +SecureNative secureNative = SecureNative.getInstance(); -You can build an event from HttpServletRequest or from combination between event and HttpServletRequest: +SecureNativeContext context = SecureNative.contextBuilder() + .withIp("127.0.0.1") + .withClientToken("SECURED_CLIENT_TOKEN") + .withHeaders(Maps.defaultBuilder() + .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") + .build()) + .build(); + +EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + +secureNative.track(eventOptions); + ``` +You can also create request context from HttpServletRequest: ```java - @RequestMapping("/track") - public String track( HttpServletRequest request, HttpServletResponse response) { - try { - secureNative = new SecureNative(API_KEY,new SecureNativeOptions()); - Event e = new SnEvent.EventBuilder(EventTypes.LOG_IN.getType()). - withUser(new User("","","chuck@norris.com")). - build(); - Event event = secureNative.buildEventFromHttpServletRequest(request, e); - secureNative.track(event); - - - } catch (SecureNativeSDKException e) { - e.printStackTrace(); - return "Api key is not valid"; - } - return "tracked"; - } - +@RequestMapping("/track") +public String track(HttpServletRequest request, HttpServletResponse response) { + SecureNativeContext context = SecureNative.contextBuilder() + .fromHttpServletRequest(request); + + EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + + secureNative.track(eventOptions); +} ``` - - - - -## Verification events - -**Example** - -```java - @RequestMapping("/verify") - public String verify(HttpServletRequest request, HttpServletResponse response) { - try { - secureNative = new SecureNative(API_KEY,new SecureNativeOptions()); - } catch (SecureNativeSDKException e) { - e.printStackTrace(); - return "Api key is not valid"; - } - secureNative.verify(new SnEvent.EventBuilder(EventTypes.LOG_IN.getType()).withUser(new User("1","Dan","Dan@Dan.dan")).withIp(ip).withRemoteIP(remoteIP).withUserAgent(userAgent).build()); -); - return "verify"; - } - -``` -## Flow events +## Verify events **Example** ```java - @RequestMapping("/flow") - public String flow( HttpServletRequest request, HttpServletResponse response) { - try { - secureNative = new SecureNative(API_KEY,new SecureNativeOptions()); - } catch (SecureNativeSDKException e) { - e.printStackTrace(); - return "Api key is not valid"; - } - secureNative.flow(1,new SnEvent.EventBuilder(EventTypes.LOG_IN.getType()).withUser(new User("1","Dan","Dan@Dan.dan")).withIp(ip).withRemoteIP(remoteIP).withUserAgent(userAgent).build()); - return "flow"; - } +@RequestMapping("/track") +public String track(HttpServletRequest request, HttpServletResponse response) { + SecureNativeContext context = SecureNative.contextBuilder() + .fromHttpServletRequest(request); + + EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + + VerifyResult verifyResult = secureNative.verify(eventOptions); + verifyResult.getRiskLevel() // Low, Medium, High + verifyResult.score() // Risk score: 0 -1 (0 - Very Low, 1 - Very High) + verifyResult.getTriggers() // ["TOR", "New IP", "New City"] +} ``` -## Webhook entry filter +## Webhook signature verification Apply our filter to verify the request is from us, example in spring: ```java - - @Bean - public FilterRegistrationBean filterWebhook() throws SecureNativeSDKException { - FilterRegistrationBean registrationBean = new FilterRegistrationBean(); - VerifyWebHookMiddleware customURLFilter = new VerifyWebHookMiddleware("API KEY"); - registrationBean.setFilter(customURLFilter); - return registrationBean; - } - ``` - -[Spring](https://github.com/securenative/securenative-java/tree/master/spring) or any web application that uses javax.servlet - -[akka-http](https://github.com/securenative/securenative-java/tree/master/akka-http) \ No newline at end of file +@RequestMapping("/webhook") +public String webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { + SecureNative secureNative = SecureNative.getInstance(); + + // Checks if request if verified + Boolean isVerified = secureNative.verifyRequestPayload(request); +} + ``` \ No newline at end of file From 624c2d5a328fa6da54f22ff7d04026a3eb1db149 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 3 May 2020 20:24:57 +0300 Subject: [PATCH 04/82] Updated readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3bae60c..f746e70 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ You can also create request context from HttpServletRequest: ```java @RequestMapping("/track") -public String track(HttpServletRequest request, HttpServletResponse response) { +public void track(HttpServletRequest request, HttpServletResponse response) { SecureNativeContext context = SecureNative.contextBuilder() .fromHttpServletRequest(request); @@ -115,7 +115,7 @@ public String track(HttpServletRequest request, HttpServletResponse response) { ```java @RequestMapping("/track") -public String track(HttpServletRequest request, HttpServletResponse response) { +public void track(HttpServletRequest request, HttpServletResponse response) { SecureNativeContext context = SecureNative.contextBuilder() .fromHttpServletRequest(request); @@ -144,7 +144,7 @@ Apply our filter to verify the request is from us, example in spring: ```java @RequestMapping("/webhook") -public String webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { +public void webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { SecureNative secureNative = SecureNative.getInstance(); // Checks if request if verified From 24b5a354ba83a479ad609277102a9f2f5bda2aeb Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 4 May 2020 15:25:12 +0300 Subject: [PATCH 05/82] Added context from request tests --- .../SecureNativeContextBuilderTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java new file mode 100644 index 0000000..47d15a0 --- /dev/null +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -0,0 +1,55 @@ +package com.securenative.context; + +import com.securenative.Maps; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class SecureNativeContextBuilderTest { + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Create context from http servlet request test") + public void createContextFromHttpServletRequestTest(){ + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.setRequestURI("/login"); + request.setQueryString("param1=value1¶m2=value2"); + request.setMethod("Post"); + request.setRemoteAddr("51.68.201.122"); + request.addHeader("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); + + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) + .build(); + + assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); + assertThat(context.getIp()).isEqualTo("51.68.201.122"); + assertThat(context.getMethod()).isEqualTo("Post"); + assertThat(context.getUrl()).isEqualTo("/login"); + assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); + assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); + assertThat(context.getBody()).isNull(); + } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Create empty context") + public void createEmptyContextTest() { + SecureNativeContext context = SecureNativeContextBuilder.defaultContextBuilder() + .build(); + + assertThat(context.getClientToken()).isNull(); + assertThat(context.getIp()).isNull(); + assertThat(context.getMethod()).isNull(); + assertThat(context.getUrl()).isNull(); + assertThat(context.getRemoteIp()).isNull(); + assertThat(context.getHeaders()).isNull(); + assertThat(context.getBody()).isNull(); + } +} + From e27b57c47c1aedb29c1a78280583d114c1f4daac Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 4 May 2020 15:37:43 +0300 Subject: [PATCH 06/82] Add more context tests --- .../SecureNativeContextBuilderTest.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java index 47d15a0..e448b3d 100644 --- a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -38,8 +38,8 @@ public void createContextFromHttpServletRequestTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) - @DisplayName("Create empty context") - public void createEmptyContextTest() { + @DisplayName("Create default context builder") + public void createDefaultContextBuilderTest() { SecureNativeContext context = SecureNativeContextBuilder.defaultContextBuilder() .build(); @@ -51,5 +51,32 @@ public void createEmptyContextTest() { assertThat(context.getHeaders()).isNull(); assertThat(context.getBody()).isNull(); } + + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Create custom context with ContextBuilder test") + public void createCustomContextWithContextBuilderTest() { + SecureNativeContext context = SecureNativeContextBuilder + .defaultContextBuilder() + .withUrl("/some-url") + .withClientToken("SECRET_TOKEN") + .withIp("10.0.0.0") + .withBody("{ \"name\": \"YOUR_NAME\" }") + .withMethod("Get") + .withRemoteIp("10.0.0.1") + .withHeaders(Maps.defaultBuilder() + .put("header1", "value1") + .build()) + .build(); + assertThat(context.getUrl()).isEqualTo("/some-url"); + assertThat(context.getClientToken()).isEqualTo("SECRET_TOKEN"); + assertThat(context.getIp()).isEqualTo("10.0.0.0"); + assertThat(context.getBody()).isEqualTo("{ \"name\": \"YOUR_NAME\" }"); + assertThat(context.getMethod()).isEqualTo("Get"); + assertThat(context.getRemoteIp()).isEqualTo("10.0.0.1"); + assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder() + .put("header1", "value1") + .build()); + } } From bb242f0e000376fa454cb2e00394bd8abffa3883 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 4 May 2020 22:38:54 +0300 Subject: [PATCH 07/82] Refactoring and more tests --- .../java/com/securenative/ApiManagerImpl.java | 8 +- .../java/com/securenative/ResourceStream.java | 6 + .../com/securenative/ResourceStreamImpl.java | 10 + .../java/com/securenative/SecureNative.java | 5 +- .../config/ConfigurationManager.java | 16 +- .../SecureNativeConfigurationBuilder.java | 4 +- .../context/SecureNativeContextBuilder.java | 28 +- .../com/securenative/enums/ActionType.java | 8 - .../java/com/securenative/enums/ApiRoute.java | 10 +- .../com/securenative/enums/EventTypes.java | 3 + .../securenative/enums/FailoverStrategy.java | 28 +- .../exceptions/SecureNativeSDKException.java | 1 - .../SecureNativeSDKIllegalStateException.java | 7 + .../com/securenative/ApiManagerImplTest.java | 6 +- .../com/securenative/EventManagerTest.java | 2 +- .../com/securenative/SecureNativeTest.java | 5 +- .../config/ConfigurationManagerTest.java | 264 ++++++++++++++++++ .../SecureNativeContextBuilderTest.java | 39 ++- 18 files changed, 392 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/securenative/ResourceStream.java create mode 100644 src/main/java/com/securenative/ResourceStreamImpl.java delete mode 100644 src/main/java/com/securenative/enums/ActionType.java create mode 100644 src/main/java/com/securenative/exceptions/SecureNativeSDKIllegalStateException.java create mode 100644 src/test/java/com/securenative/config/ConfigurationManagerTest.java diff --git a/src/main/java/com/securenative/ApiManagerImpl.java b/src/main/java/com/securenative/ApiManagerImpl.java index 577cbb0..958232b 100644 --- a/src/main/java/com/securenative/ApiManagerImpl.java +++ b/src/main/java/com/securenative/ApiManagerImpl.java @@ -10,8 +10,6 @@ import com.securenative.models.VerifyResult; import com.securenative.models.SDKEvent; -import java.io.IOException; - public class ApiManagerImpl implements ApiManager { private final EventManager eventManager; private final SecureNativeOptions options; @@ -25,7 +23,7 @@ public ApiManagerImpl(EventManager eventManager, SecureNativeOptions options) th @Override public void track(EventOptions eventOptions) { logger.info("Track event call"); - String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.TRACK.getRoute()); + String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.TRACK.getApiRoute()); Event event = new SDKEvent(eventOptions, this.options); this.eventManager.sendAsync(event,requestUrl, true); } @@ -33,13 +31,13 @@ public void track(EventOptions eventOptions) { @Override public VerifyResult verify(EventOptions eventOptions) { logger.info("Verify event call"); - String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.VERIFY.getRoute()); + String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.VERIFY.getApiRoute()); Event event = new SDKEvent(eventOptions, this.options); try { return this.eventManager.sendSync(VerifyResult.class , event, requestUrl); } catch (Exception ex) { logger.error("Failed to call verify", ex); - return this.options.getFailoverStrategy() == FailoverStrategy.FailOpen ? + return this.options.getFailoverStrategy() == FailoverStrategy.FAIL_OPEN ? new VerifyResult(RiskLevel.LOW, 0, new String[0]) : new VerifyResult(RiskLevel.HIGH, 1, new String[0]); } diff --git a/src/main/java/com/securenative/ResourceStream.java b/src/main/java/com/securenative/ResourceStream.java new file mode 100644 index 0000000..81412f9 --- /dev/null +++ b/src/main/java/com/securenative/ResourceStream.java @@ -0,0 +1,6 @@ +package com.securenative; +import java.io.InputStream; + +public interface ResourceStream { + InputStream getInputStream(String name); +} \ No newline at end of file diff --git a/src/main/java/com/securenative/ResourceStreamImpl.java b/src/main/java/com/securenative/ResourceStreamImpl.java new file mode 100644 index 0000000..8e98d68 --- /dev/null +++ b/src/main/java/com/securenative/ResourceStreamImpl.java @@ -0,0 +1,10 @@ +package com.securenative; + +import java.io.InputStream; + +public class ResourceStreamImpl implements ResourceStream { + @Override + public InputStream getInputStream(String name) { + return SecureNative.class.getClassLoader().getResourceAsStream(name); + } +} diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java index c16ed2f..023ab81 100644 --- a/src/main/java/com/securenative/SecureNative.java +++ b/src/main/java/com/securenative/SecureNative.java @@ -6,6 +6,7 @@ import com.securenative.context.SecureNativeContextBuilder; import com.securenative.exceptions.SecureNativeConfigException; import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.exceptions.SecureNativeSDKIllegalStateException; import com.securenative.http.SecureNativeHTTPClient; import com.securenative.models.EventOptions; import com.securenative.models.VerifyResult; @@ -55,9 +56,9 @@ public static SecureNative init() throws SecureNativeSDKException, SecureNativeC return init(secureNativeOptions); } - public static SecureNative getInstance() throws SecureNativeSDKException { + public static SecureNative getInstance() throws SecureNativeSDKIllegalStateException { if (secureNative == null) { - throw new SecureNativeSDKException("Secure Native SDK wasn't initialized yet, please call init first"); + throw new SecureNativeSDKIllegalStateException(); } return secureNative; } diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index 245cf7d..2968dc9 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -1,7 +1,10 @@ package com.securenative.config; +import com.securenative.ResourceStreamImpl; +import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; import com.securenative.SecureNative; +import com.securenative.ResourceStream; import com.securenative.utils.Utils; import java.io.IOException; @@ -12,7 +15,7 @@ public class ConfigurationManager { private static final String DEFAULT_CONFIG_FILE = "securenative.properties"; private static final String CUSTOM_CONFIG_FILE_ENV_NAME = "SECURENATIVE_CONFIG_FILE"; - + private static ResourceStream resourceStream = new ResourceStreamImpl(); private static String getEnvOrDefault(String envName, String defaultValue) { String envValue = System.getenv(envName); if (envValue != null) { @@ -26,10 +29,14 @@ private static String getEnvOrDefault(String envName, String defaultValue) { return defaultValue; } + public static void setResourceStream(ResourceStream resourceStream) { + ConfigurationManager.resourceStream = resourceStream; + } + private static Properties loadProperties(Properties properties, InputStream inputStream) { try (final InputStream stream = inputStream) { properties.load(stream); - } catch (IOException e) { + } catch (Exception e) { return new Properties(); } return properties; @@ -39,7 +46,7 @@ private static Properties readResourceFile(String resourcePath) { Properties properties = new Properties(); URL resourceUrl = SecureNative.class.getClassLoader().getResource(resourcePath); if (resourceUrl != null) { - InputStream resourceStream = SecureNative.class.getClassLoader().getResourceAsStream(resourcePath); + InputStream resourceStream = ConfigurationManager.resourceStream.getInputStream(resourcePath); properties = loadProperties(properties, resourceStream); } return properties; @@ -69,7 +76,8 @@ public static SecureNativeOptions loadConfig() throws SecureNativeConfigExceptio .withTimeout(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_TIMEOUT", defaultOptions.getTimeout()), defaultOptions.getTimeout())) .withAutoSend(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_AUTO_SEND", defaultOptions.getAutoSend()), defaultOptions.getAutoSend())) .withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled())) - .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())); + .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())) + .withFailoverStrategy(FailoverStrategy.fromString(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy()),defaultOptions.getFailoverStrategy())); return builder.build(); } diff --git a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java index c2b8c11..a3b1f12 100644 --- a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java +++ b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java @@ -1,6 +1,5 @@ package com.securenative.config; -import com.securenative.exceptions.SecureNativeConfigException; import com.securenative.enums.FailoverStrategy; public class SecureNativeConfigurationBuilder { @@ -61,7 +60,7 @@ public static SecureNativeConfigurationBuilder defaultConfigBuilder() { .withAutoSend(true) .withDisable(false) .withLogLevel("fatal") - .withFailoverStrategy(FailoverStrategy.FailOpen); + .withFailoverStrategy(FailoverStrategy.FAIL_OPEN); } public SecureNativeConfigurationBuilder withApiKey(String apiKey) { @@ -112,6 +111,5 @@ public SecureNativeConfigurationBuilder withFailoverStrategy(FailoverStrategy fa public SecureNativeOptions build() { return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy); - } } diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java index b329bc9..5dbeb11 100644 --- a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -13,37 +13,37 @@ private SecureNativeContextBuilder() { this.context = new SecureNativeContext(); } - public SecureNativeContextBuilder withClientToken(String clientToken) { + public SecureNativeContextBuilder clientToken(String clientToken) { this.context.setClientToken(clientToken); return this; } - public SecureNativeContextBuilder withIp(String ip) { + public SecureNativeContextBuilder ip(String ip) { this.context.setIp(ip); return this; } - public SecureNativeContextBuilder withRemoteIp(String remoteIp) { + public SecureNativeContextBuilder remoteIp(String remoteIp) { this.context.setRemoteIp(remoteIp); return this; } - public SecureNativeContextBuilder withHeaders(Map headers) { + public SecureNativeContextBuilder headers(Map headers) { this.context.setHeaders(headers); return this; } - public SecureNativeContextBuilder withUrl(String url) { + public SecureNativeContextBuilder url(String url) { this.context.setUrl(url); return this; } - public SecureNativeContextBuilder withMethod(String method) { + public SecureNativeContextBuilder method(String method) { this.context.setMethod(method); return this; } - public SecureNativeContextBuilder withBody(String body) { + public SecureNativeContextBuilder body(String body) { this.context.setBody(body); return this; } @@ -61,13 +61,13 @@ public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletReque } return new SecureNativeContextBuilder() - .withUrl(request.getRequestURI()) - .withMethod(request.getMethod()) - .withHeaders(headers) - .withClientToken(clientToken) - .withIp(RequestUtils.getClientIpFromRequest(request, headers)) - .withRemoteIp(RequestUtils.getRemoteIpFromRequest(request)) - .withBody(null); + .url(request.getRequestURI()) + .method(request.getMethod()) + .headers(headers) + .clientToken(clientToken) + .ip(RequestUtils.getClientIpFromRequest(request, headers)) + .remoteIp(RequestUtils.getRemoteIpFromRequest(request)) + .body(null); } public SecureNativeContext build(){ diff --git a/src/main/java/com/securenative/enums/ActionType.java b/src/main/java/com/securenative/enums/ActionType.java deleted file mode 100644 index e9b7aef..0000000 --- a/src/main/java/com/securenative/enums/ActionType.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.securenative.enums; - -public enum ActionType { - ALLOW, - BLOCK, - REDIRECT, - MFA -} diff --git a/src/main/java/com/securenative/enums/ApiRoute.java b/src/main/java/com/securenative/enums/ApiRoute.java index 5d91efa..2ed7239 100644 --- a/src/main/java/com/securenative/enums/ApiRoute.java +++ b/src/main/java/com/securenative/enums/ApiRoute.java @@ -4,13 +4,13 @@ public enum ApiRoute { TRACK("track"), VERIFY("verify"); - private String route; + private String apiRoute; - public String getRoute() { - return route; + public String getApiRoute() { + return apiRoute; } - ApiRoute(String route) { - this.route = route; + ApiRoute(String apiRoute) { + this.apiRoute = apiRoute; } } \ No newline at end of file diff --git a/src/main/java/com/securenative/enums/EventTypes.java b/src/main/java/com/securenative/enums/EventTypes.java index f229736..176dd45 100644 --- a/src/main/java/com/securenative/enums/EventTypes.java +++ b/src/main/java/com/securenative/enums/EventTypes.java @@ -1,5 +1,7 @@ package com.securenative.enums; +import com.fasterxml.jackson.annotation.JsonValue; + public enum EventTypes { LOG_IN("sn.user.login"), LOG_IN_CHALLENGE("sn.user.login.challenge"), @@ -21,6 +23,7 @@ public enum EventTypes { PAGE_VIEW("sn.user.page.view"), VERIFY("sn.verify"); + @JsonValue public String getType() { return type; } diff --git a/src/main/java/com/securenative/enums/FailoverStrategy.java b/src/main/java/com/securenative/enums/FailoverStrategy.java index 3b44e86..d4ec4ea 100644 --- a/src/main/java/com/securenative/enums/FailoverStrategy.java +++ b/src/main/java/com/securenative/enums/FailoverStrategy.java @@ -1,6 +1,28 @@ package com.securenative.enums; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + public enum FailoverStrategy { - FailOpen, - FailClosed -} + FAIL_OPEN("fail-open"), + FAIL_CLOSED("fail-closed"); + + private String failoverStrategy; + + @JsonValue + public String getFailoverStrategy() { + return failoverStrategy; + } + + public static FailoverStrategy fromString(String key, FailoverStrategy failoverStrategy) { + try { + return FailoverStrategy.valueOf(key.replace("-", "_").toUpperCase()); + }catch (IllegalArgumentException ex){ + return failoverStrategy; + } + } + + FailoverStrategy(String failoverStrategy) { + this.failoverStrategy = failoverStrategy; + } +} \ No newline at end of file diff --git a/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java b/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java index 79c2c4a..9bc0c05 100644 --- a/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java +++ b/src/main/java/com/securenative/exceptions/SecureNativeSDKException.java @@ -7,4 +7,3 @@ public SecureNativeSDKException(String message) { } - diff --git a/src/main/java/com/securenative/exceptions/SecureNativeSDKIllegalStateException.java b/src/main/java/com/securenative/exceptions/SecureNativeSDKIllegalStateException.java new file mode 100644 index 0000000..2972e04 --- /dev/null +++ b/src/main/java/com/securenative/exceptions/SecureNativeSDKIllegalStateException.java @@ -0,0 +1,7 @@ +package com.securenative.exceptions; + +public class SecureNativeSDKIllegalStateException extends SecureNativeSDKException { + public SecureNativeSDKIllegalStateException() { + super("Secure Native SDK wasn't initialized yet, please call init first"); + } +} diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java index 617f6d0..67a3965 100644 --- a/src/test/java/com/securenative/ApiManagerImplTest.java +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -35,9 +35,9 @@ public class ApiManagerImplTest extends HTTPServerMock { public ApiManagerImplTest() throws SecureNativeInvalidOptionsException { // init default event for tests SecureNativeContext context = SecureNative.contextBuilder() - .withIp("127.0.0.1") - .withClientToken("SECURED_CLIENT_TOKEN") - .withHeaders(Maps.defaultBuilder() + .ip("127.0.0.1") + .clientToken("SECURED_CLIENT_TOKEN") + .headers(Maps.defaultBuilder() .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") .build()) .build(); diff --git a/src/test/java/com/securenative/EventManagerTest.java b/src/test/java/com/securenative/EventManagerTest.java index 45309dd..3447e47 100644 --- a/src/test/java/com/securenative/EventManagerTest.java +++ b/src/test/java/com/securenative/EventManagerTest.java @@ -115,7 +115,7 @@ public void ShouldNotRetrySendingAsyncEventWhenStatusCode200Test() throws Secure } @Test - @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + @Timeout(value = 4000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should not retry sending async event when status code 401") public void ShouldNotRetrySendingAsyncEventWhenStatusCode401Test() throws SecureNativeSDKException, InterruptedException { configBuilder = ConfigurationManager.configBuilder() diff --git a/src/test/java/com/securenative/SecureNativeTest.java b/src/test/java/com/securenative/SecureNativeTest.java index 650d34c..088dd72 100644 --- a/src/test/java/com/securenative/SecureNativeTest.java +++ b/src/test/java/com/securenative/SecureNativeTest.java @@ -4,6 +4,7 @@ import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; import com.securenative.exceptions.SecureNativeSDKException; +import com.securenative.exceptions.SecureNativeSDKIllegalStateException; import org.junit.jupiter.api.*; import org.junitpioneer.jupiter.SetSystemProperty; @@ -35,7 +36,7 @@ public void initSDKWithPublicMethodsDefinedTest() { @Order(2) @DisplayName("Should throw when getting SDK instance without init") public void getSDKInstanceWithoutInitThrowsTest() { - assertThrows(SecureNativeSDKException.class, SecureNative::getInstance); + assertThrows(SecureNativeSDKIllegalStateException.class, SecureNative::getInstance); } @Test @@ -78,7 +79,7 @@ public void initSDKWithApiKeyAndDefaultsTest() throws SecureNativeConfigExceptio assertThat(options.getAutoSend()).isEqualTo(true); assertThat(options.getDisabled()).isEqualTo(false); assertThat(options.getLogLevel()).isEqualTo("fatal"); - assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FailOpen); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); } @Test diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java new file mode 100644 index 0000000..ac8cc28 --- /dev/null +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -0,0 +1,264 @@ +package com.securenative.config; + +import com.securenative.ResourceStreamImpl; +import com.securenative.enums.FailoverStrategy; +import com.securenative.exceptions.SecureNativeConfigException; +import org.junit.jupiter.api.*; +import org.mockito.Mockito; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ConfigurationManagerTest { + @SuppressWarnings({ "unchecked" }) + private static void setEnv(String name, String val) throws ReflectiveOperationException { + Map env = System.getenv(); + Field field = env.getClass().getDeclaredField("m"); + field.setAccessible(true); + ((Map) field.get(env)).put(name, val); + } + + @Test + @Order(1) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should parse config file correctly") + public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { + String config = String.join(System.getProperty("line.separator"), + "SECURENATIVE_API_KEY=SOME_API_KEY", + "SECURENATIVE_APP_NAME=SOME_APP_NAME", + "SECURENATIVE_API_URL=SOME_API_URL", + "SECURENATIVE_INTERVAL=1000", + "SECURENATIVE_HEARTBEAT_INTERVAL=5000", + "SECURENATIVE_MAX_EVENTS=100", + "SECURENATIVE_TIMEOUT=1500", + "SECURENATIVE_AUTO_SEND=true", + "SECURENATIVE_DISABLE=false", + "SECURENATIVE_LOG_LEVEL=fatal", + "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + assertThat(options.getApiKey()).isEqualTo("SOME_API_KEY"); + assertThat(options.getApiUrl()).isEqualTo("SOME_API_URL"); + assertThat(options.getAutoSend()).isEqualTo(true); + assertThat(options.getDisabled()).isEqualTo( false); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); + assertThat(options.getInterval()).isEqualTo(1000); + assertThat(options.getLogLevel()).isEqualTo("fatal"); + assertThat(options.getMaxEvents()).isEqualTo(100); + assertThat(options.getTimeout()).isEqualTo(1500); + } + + @Test + @Order(2) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should ignore unknown config file entries") + public void IgnoreUnknownConfigInPropertiesFileTest() throws SecureNativeConfigException { + String config = String.join(System.getProperty("line.separator"), + "SECURENATIVE_UNKNOWN_KEY=SOME_UNKNOWN_KEY", + "SECURENATIVE_TIMEOUT=7500"); + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + assertThat(options.getTimeout()).isEqualTo(7500); + } + + + @Test + @Order(3) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should not throw when parsing invalid config file") + public void handleInvalidConfigFileTest() throws SecureNativeConfigException { + String config = "{bla bla bla}"; + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + } + + @Test + @Order(4) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should ignore invalid config file entries") + public void IgnoreInvalidConfigFileEntriesTest() throws SecureNativeConfigException { + String config = String.join(System.getProperty("line.separator"), + "SECURENATIVE_API_KEY=1", + "SECURENATIVE_API_URL=3", + "SECURENATIVE_TIMEOUT=bad timeout", + "SECURENATIVE_FAILOVER_STRATEGY=fail-what"); + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + } + + @Test + @Order(5) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should get default config when config file and env variables are missing") + public void loadDefaultConfigTest() throws SecureNativeConfigException { + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(null); + + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options.getApiKey()).isNull(); + assertThat(options.getApiUrl()).isEqualTo("https://api.securenative.com/collector/api/v1"); + assertThat(options.getInterval()).isEqualTo(1000); + assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getMaxEvents()).isEqualTo(1000); + assertThat(options.getAutoSend()).isEqualTo(true); + assertThat(options.getAutoSend()).isEqualTo(true); + assertThat(options.getDisabled()).isEqualTo(false); + assertThat(options.getLogLevel()).isEqualTo("fatal"); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + } + + @Test + @Order(6) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should get config via env variables") + public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { + setEnv("SECURENATIVE_API_KEY", "SOME_API_KEY"); + setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); + setEnv("SECURENATIVE_INTERVAL", "6000"); + setEnv("SECURENATIVE_MAX_EVENTS", "700"); + setEnv("SECURENATIVE_TIMEOUT", "1700"); + setEnv("SECURENATIVE_AUTO_SEND", "false"); + setEnv("SECURENATIVE_DISABLE", "true"); + setEnv("SECURENATIVE_LOG_LEVEL", "fatal"); + setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-closed"); + + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options.getApiKey()).isEqualTo("SOME_API_KEY"); + assertThat(options.getApiUrl()).isEqualTo("SOME_API_URL"); + assertThat(options.getInterval()).isEqualTo(6000); + assertThat(options.getTimeout()).isEqualTo(1700); + assertThat(options.getMaxEvents()).isEqualTo(700); + assertThat(options.getAutoSend()).isEqualTo(false); + assertThat(options.getDisabled()).isEqualTo(true); + assertThat(options.getLogLevel()).isEqualTo("fatal"); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); + + setEnv("SECURENATIVE_API_KEY", ""); + setEnv("SECURENATIVE_API_URL", ""); + setEnv("SECURENATIVE_INTERVAL", ""); + setEnv("SECURENATIVE_MAX_EVENTS", ""); + setEnv("SECURENATIVE_TIMEOUT", ""); + setEnv("SECURENATIVE_AUTO_SEND", ""); + setEnv("SECURENATIVE_DISABLE", ""); + setEnv("SECURENATIVE_LOG_LEVEL", ""); + setEnv("SECURENATIVE_FAILOVER_STRATEGY", ""); + } + + @Test + @Order(7) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should overwrite env variables with vales from config file") + public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { + String config = String.join(System.getProperty("line.separator"), + "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", + "SECURENATIVE_API_URL=API_URL_FROM_FILE", + "SECURENATIVE_INTERVAL=1000", + "SECURENATIVE_MAX_EVENTS=100", + "SECURENATIVE_TIMEOUT=1500", + "SECURENATIVE_AUTO_SEND=false", + "SECURENATIVE_DISABLE=false", + "SECURENATIVE_LOG_LEVEL=fatal", + "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); + + setEnv("SECURENATIVE_API_KEY", "API_KEY_FROM_ENV"); + setEnv("SECURENATIVE_API_URL", "API_URL_ENV"); + setEnv("SECURENATIVE_INTERVAL", "2000"); + setEnv("SECURENATIVE_MAX_EVENTS", "200"); + setEnv("SECURENATIVE_TIMEOUT", "3000"); + setEnv("SECURENATIVE_AUTO_SEND", "true"); + setEnv("SECURENATIVE_DISABLE", "true"); + setEnv("SECURENATIVE_LOG_LEVEL", "error"); + setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-open"); + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + assertThat(options.getApiKey()).isEqualTo("API_KEY_FROM_FILE"); + assertThat(options.getApiUrl()).isEqualTo("API_URL_FROM_FILE"); + assertThat(options.getInterval()).isEqualTo(1000); + assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getMaxEvents()).isEqualTo(100); + assertThat(options.getAutoSend()).isEqualTo(false); + assertThat(options.getDisabled()).isEqualTo(false); + assertThat(options.getLogLevel()).isEqualTo("fatal"); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); + + setEnv("SECURENATIVE_API_KEY", ""); + setEnv("SECURENATIVE_API_URL", ""); + setEnv("SECURENATIVE_INTERVAL", ""); + setEnv("SECURENATIVE_MAX_EVENTS", ""); + setEnv("SECURENATIVE_TIMEOUT", ""); + setEnv("SECURENATIVE_AUTO_SEND", ""); + setEnv("SECURENATIVE_DISABLE", ""); + setEnv("SECURENATIVE_LOG_LEVEL", ""); + setEnv("SECURENATIVE_FAILOVER_STRATEGY", ""); + } + + @Test + @Order(8) + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Should set defaults for invalid enum properties") + public void defaultValuesForInvalidEnumConfigPropsTest() throws SecureNativeConfigException { + String config = String.join(System.getProperty("line.separator"), + "SECURENATIVE_FAILOVER_STRATEGY=fail-something"); + + InputStream inputStream = new ByteArrayInputStream(config.getBytes()); + + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(inputStream); + + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); + + assertThat(options).isNotNull(); + assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + } +} diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java index e448b3d..2807de0 100644 --- a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Timeout; import org.springframework.mock.web.MockHttpServletRequest; +import javax.servlet.http.Cookie; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -36,6 +37,30 @@ public void createContextFromHttpServletRequestTest(){ assertThat(context.getBody()).isNull(); } + @Test + @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @DisplayName("Create context from http servlet request with cookie test") + public void createContextFromHttpServletRequestWithCookieTest(){ + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.setRequestURI("/login"); + request.setQueryString("param1=value1¶m2=value2"); + request.setMethod("Post"); + request.setRemoteAddr("51.68.201.122"); + request.setCookies(new Cookie("_sn", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a")); + + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) + .build(); + + assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); + assertThat(context.getIp()).isEqualTo("51.68.201.122"); + assertThat(context.getMethod()).isEqualTo("Post"); + assertThat(context.getUrl()).isEqualTo("/login"); + assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); + assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("Cookie", "_sn=71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); + assertThat(context.getBody()).isNull(); + } + @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Create default context builder") @@ -58,13 +83,13 @@ public void createDefaultContextBuilderTest() { public void createCustomContextWithContextBuilderTest() { SecureNativeContext context = SecureNativeContextBuilder .defaultContextBuilder() - .withUrl("/some-url") - .withClientToken("SECRET_TOKEN") - .withIp("10.0.0.0") - .withBody("{ \"name\": \"YOUR_NAME\" }") - .withMethod("Get") - .withRemoteIp("10.0.0.1") - .withHeaders(Maps.defaultBuilder() + .url("/some-url") + .clientToken("SECRET_TOKEN") + .ip("10.0.0.0") + .body("{ \"name\": \"YOUR_NAME\" }") + .method("Get") + .remoteIp("10.0.0.1") + .headers(Maps.defaultBuilder() .put("header1", "value1") .build()) .build(); From 0838d85065c9a4d4003e9c41dc695736c78cd840 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 5 May 2020 09:34:27 +0300 Subject: [PATCH 08/82] Changed usertraits construction --- README.md | 6 +++--- .../java/com/securenative/EventOptionsBuilder.java | 14 ++++++++++++-- .../java/com/securenative/ApiManagerImplTest.java | 8 ++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f746e70..d336d8a 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ SecureNativeContext context = SecureNative.contextBuilder() EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .userTraits("USER_NAME", "USER_EMAIL") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -95,7 +95,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .userTraits("USER_NAME", "USER_EMAIL") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -121,7 +121,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .userTraits("USER_NAME", "USER_EMAIL") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index 3e15721..bb195f8 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -32,8 +32,18 @@ public EventOptionsBuilder userId(String userId) { return this; } - public EventOptionsBuilder userTraits(UserTraits userTraits) { - this.eventOptions.setUserTraits(userTraits); + public EventOptionsBuilder userTraits(String name) { + this.eventOptions.setUserTraits(new UserTraits(name)); + return this; + } + + public EventOptionsBuilder userTraits(String name, String email) { + this.eventOptions.setUserTraits(new UserTraits(name, email)); + return this; + } + + public EventOptionsBuilder userTraits(String name, String email, Date createdAt) { + this.eventOptions.setUserTraits(new UserTraits(name, email, createdAt)); return this; } diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java index 67a3965..a942061 100644 --- a/src/test/java/com/securenative/ApiManagerImplTest.java +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -44,7 +44,7 @@ public ApiManagerImplTest() throws SecureNativeInvalidOptionsException { eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits(new UserTraits("'USER_NAME'", "'USER_EMAIL'")) + .userTraits("USER_NAME", "USER_EMAIL") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -76,7 +76,7 @@ public void ShouldCallTrackEventTest() throws SecureNativeSDKException, Interrup // ensure event to be sent RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; - String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"USER_NAME\",\"email\":\"USER_EMAIL\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; assertThat(body).isNotNull(); JSONAssert.assertEquals(expected, body, false); assertThat(new JSONObject(body).has("rid")).isTrue(); @@ -198,7 +198,7 @@ public void ShouldCallVerifyEventTest() throws SecureNativeSDKException, JsonPro RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); String lastRequestBody = lastRequest != null ? lastRequest.getBody().readUtf8() : null; - String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"USER_NAME\",\"email\":\"USER_EMAIL\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; assertThat(lastRequestBody).isNotNull(); JSONAssert.assertEquals(expected, lastRequestBody, false); assertThat(new JSONObject(lastRequestBody).has("rid")).isTrue(); @@ -229,7 +229,7 @@ public void ShouldFailVerifyEventCallWhenUnauthorizedTest() throws SecureNativeS RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); String lastRequestBody = lastRequest != null ? lastRequest.getBody().readUtf8() : null; - String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"'USER_NAME'\",\"email\":\"'USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; + String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"USER_NAME'\",\"email\":\"USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; assertThat(lastRequestBody).isNotNull(); } From ab8a55711f812d42d1abd83bbaff2b67cc4b73d8 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Tue, 5 May 2020 22:01:20 +0300 Subject: [PATCH 09/82] Add missing sonatype settings --- pom.xml | 226 +++++++++++++++++++++++++++------------------------- pom.xml.asc | 11 +++ 2 files changed, 130 insertions(+), 107 deletions(-) create mode 100644 pom.xml.asc diff --git a/pom.xml b/pom.xml index b37cf81..9dcc945 100644 --- a/pom.xml +++ b/pom.xml @@ -1,14 +1,14 @@ - + 4.0.0 - io.securenative + com.securenative.java securenative-java jar - 0.3.0 + 0.3.2 https://github.com/securenative/securenative-java - + ${project.groupId}:${project.artifactId}:${project.version} SecureNative user monitoring sdk. @@ -45,12 +45,6 @@ http://github.com/securenative/securenative-java/tree/master - - 1.6 - 1.6 - 0.2.3 - - deploy @@ -59,7 +53,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.6.7 true ossrh @@ -164,100 +158,118 @@ - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - maven-assembly-plugin - - - - your.MainClass - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + 3.8.1 + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + maven-deploy-plugin + 2.8.2 + + + default-deploy + deploy + + deploy + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.1 + + + + ${java.home}/bin/javadoc + false + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + + + + UTF-8 + UTF-8 + 1.6 + 1.6 + 0.2.3 + \ No newline at end of file diff --git a/pom.xml.asc b/pom.xml.asc new file mode 100644 index 0000000..79ee87b --- /dev/null +++ b/pom.xml.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- + +iQEzBAABCAAdFiEE3Et7fS4h12t+F7BE7tXV6OHJmUQFAl550F8ACgkQ7tXV6OHJ +mURXqgf9Edq8gvhESTwstYoZnjegKvSBVaz7lBU6XFfp/3DuRwVr1xICvdiEIROZ +LOCcXcrLqnLproWrIA0Cd3ZeDPu1xwL9HRAD10f5v03jrZgszxIQxV/besphhAuf +07lncPD/OMoVoAhQLOOCTZEYAOyzsb6H9BT4wEr1SYb/GUoIxC5471TYYe/MJ8+b +o0bxRZiR2lX8engsChkc9r1I0sPkkFIITw/NKlbeZdRemdQuH9cLIZyMR1h+C99a +2O1uSXS/h2Rq+SbUh8HQ8VtMPNHsGPQpVdCa4JrA6Z9ETj68PNUraZMfAYU5XMQg +yQKs1LbCgdUAX7UtNhYXiQZa48udug== +=Ilre +-----END PGP SIGNATURE----- From 130f8fec66d8c73994f52a5edb8ef142aeea0f2e Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 7 May 2020 12:52:15 +0300 Subject: [PATCH 10/82] User okhttp version 4.0.0 --- README.md | 3 ++- pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d336d8a..a88960d 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,8 @@ You can also create request context from HttpServletRequest: @RequestMapping("/track") public void track(HttpServletRequest request, HttpServletResponse response) { SecureNativeContext context = SecureNative.contextBuilder() - .fromHttpServletRequest(request); + .fromHttpServletRequest(request) + .build(); EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") diff --git a/pom.xml b/pom.xml index b37cf81..a19f7ea 100644 --- a/pom.xml +++ b/pom.xml @@ -111,7 +111,7 @@ com.squareup.okhttp3 okhttp - 4.5.0 + 4.0.0 org.mockito @@ -134,7 +134,7 @@ com.squareup.okhttp3 mockwebserver - 4.6.0 + 4.0.0 test From e22e22913d5bb9d419bcb9697b743b0d9c2c5882 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 7 May 2020 12:55:23 +0300 Subject: [PATCH 11/82] Bump sdk version --- README.md | 3 ++- pom.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a88960d..25051ca 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,8 @@ public void track(HttpServletRequest request, HttpServletResponse response) { @RequestMapping("/track") public void track(HttpServletRequest request, HttpServletResponse response) { SecureNativeContext context = SecureNative.contextBuilder() - .fromHttpServletRequest(request); + .fromHttpServletRequest(request) + .build(); EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") diff --git a/pom.xml b/pom.xml index f208d62..1df40d6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.2 + 0.3.3 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 2bc44c93b997878d05e5373d216dd2ad267ab1df Mon Sep 17 00:00:00 2001 From: alexivsn <45174009+alexivsn@users.noreply.github.com> Date: Thu, 7 May 2020 15:00:11 +0300 Subject: [PATCH 12/82] Added ci --- .github/workflows/ci.yml | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2efe59f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven +name: CI + +on: + pull_request: + branches: + - master + - dev + - dev-* + +jobs: + build: + + runs-on: ubuntu-latest + steps: + - name: Notify slack success + if: success() + id: slack # IMPORTANT: reference this step ID value in future Slack steps + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + channel: github-actions + status: STARTING + color: warning + + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Notify slack success + if: success() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: SUCCESS + color: good + + - name: Notify slack fail + if: failure() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: FAILED + color: danger From 000f942754df80e388e367eb87c3b75d16c8e67f Mon Sep 17 00:00:00 2001 From: alexivsn <45174009+alexivsn@users.noreply.github.com> Date: Thu, 7 May 2020 15:03:12 +0300 Subject: [PATCH 13/82] Updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 25051ca..dc2d4cf 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ Apply our filter to verify the request is from us, example in spring: public void webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { SecureNative secureNative = SecureNative.getInstance(); - // Checks if request if verified + // Checks if request is verified Boolean isVerified = secureNative.verifyRequestPayload(request); } - ``` \ No newline at end of file + ``` From e60d0c945e146da0f0ae2afc0ad3776b512a38d0 Mon Sep 17 00:00:00 2001 From: alexivsn <45174009+alexivsn@users.noreply.github.com> Date: Thu, 7 May 2020 15:16:16 +0300 Subject: [PATCH 14/82] Updated ci --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2efe59f..b52c449 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,3 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven name: CI on: @@ -10,7 +8,7 @@ on: - dev-* jobs: - build: + ci: runs-on: ubuntu-latest steps: From 89dfaefb11e6d402c6426770f9d7767a0ebd33d9 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Thu, 7 May 2020 21:18:06 +0300 Subject: [PATCH 15/82] Fix tests running --- pom.xml | 10 ++++++++ .../config/ConfigurationManager.java | 6 ++--- .../com/securenative/SecureNativeTest.java | 2 +- .../config/ConfigurationManagerTest.java | 25 +++++++++++++++++-- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 1df40d6..e097fe3 100644 --- a/pom.xml +++ b/pom.xml @@ -262,6 +262,16 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + + false + true + false + + diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index 2968dc9..01e5ad0 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -1,13 +1,12 @@ package com.securenative.config; +import com.securenative.ResourceStream; import com.securenative.ResourceStreamImpl; +import com.securenative.SecureNative; import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; -import com.securenative.SecureNative; -import com.securenative.ResourceStream; import com.securenative.utils.Utils; -import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Properties; @@ -68,7 +67,6 @@ public static SecureNativeOptions loadConfig() throws SecureNativeConfigExceptio String resourceFilePath = getEnvOrDefault(CUSTOM_CONFIG_FILE_ENV_NAME, DEFAULT_CONFIG_FILE); Properties properties = readResourceFile(resourceFilePath); - builder.withApiKey(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_KEY", defaultOptions.getApiKey())) .withApiUrl(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_URL", defaultOptions.getApiUrl())) .withInterval(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_INTERVAL", defaultOptions.getInterval()), defaultOptions.getInterval())) diff --git a/src/test/java/com/securenative/SecureNativeTest.java b/src/test/java/com/securenative/SecureNativeTest.java index 088dd72..a13e45b 100644 --- a/src/test/java/com/securenative/SecureNativeTest.java +++ b/src/test/java/com/securenative/SecureNativeTest.java @@ -1,5 +1,6 @@ package com.securenative; +import com.securenative.config.ConfigurationManager; import com.securenative.config.SecureNativeOptions; import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; @@ -129,7 +130,6 @@ public void initSDKWithBuilderTest() throws SecureNativeConfigException, SecureN public void initSDKAndLoadFromPropertiesFileTest() throws SecureNativeConfigException, SecureNativeSDKException { SecureNative secureNative = SecureNative.init(); SecureNativeOptions options = secureNative.getOptions(); - assertThat(options).extracting("apiKey", "timeout") .containsExactly("SOME_API_KEY", 2000); } diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index ac8cc28..4459151 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -60,6 +60,9 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getMaxEvents()).isEqualTo(100); assertThat(options.getTimeout()).isEqualTo(1500); + + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @Test @@ -81,6 +84,8 @@ public void IgnoreUnknownConfigInPropertiesFileTest() throws SecureNativeConfigE assertThat(options).isNotNull(); assertThat(options.getTimeout()).isEqualTo(7500); + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @@ -100,6 +105,9 @@ public void handleInvalidConfigFileTest() throws SecureNativeConfigException { SecureNativeOptions options = ConfigurationManager.loadConfig(); assertThat(options).isNotNull(); + + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @Test @@ -123,6 +131,8 @@ public void IgnoreInvalidConfigFileEntriesTest() throws SecureNativeConfigExcept assertThat(options).isNotNull(); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @Test @@ -133,6 +143,9 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); Mockito.when(resourceStream.getInputStream("securenative.properties")).thenReturn(null); + //set resource stream + ConfigurationManager.setResourceStream(resourceStream); + SecureNativeOptions options = ConfigurationManager.loadConfig(); assertThat(options.getApiKey()).isNull(); @@ -146,6 +159,8 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { assertThat(options.getDisabled()).isEqualTo(false); assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @Test @@ -153,7 +168,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { - setEnv("SECURENATIVE_API_KEY", "SOME_API_KEY"); + setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); setEnv("SECURENATIVE_INTERVAL", "6000"); setEnv("SECURENATIVE_MAX_EVENTS", "700"); @@ -168,7 +183,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, assertThat(options.getApiKey()).isEqualTo("SOME_API_KEY"); assertThat(options.getApiUrl()).isEqualTo("SOME_API_URL"); assertThat(options.getInterval()).isEqualTo(6000); - assertThat(options.getTimeout()).isEqualTo(1700); + assertThat(options.getTimeout()).isEqualTo(2000); assertThat(options.getMaxEvents()).isEqualTo(700); assertThat(options.getAutoSend()).isEqualTo(false); assertThat(options.getDisabled()).isEqualTo(true); @@ -240,6 +255,9 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE setEnv("SECURENATIVE_DISABLE", ""); setEnv("SECURENATIVE_LOG_LEVEL", ""); setEnv("SECURENATIVE_FAILOVER_STRATEGY", ""); + + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @Test @@ -260,5 +278,8 @@ public void defaultValuesForInvalidEnumConfigPropsTest() throws SecureNativeConf assertThat(options).isNotNull(); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + + // restore resource stream + ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } } From 606d57bbc067e9177a84e305a6a34e8665535962 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Thu, 7 May 2020 21:26:04 +0300 Subject: [PATCH 16/82] Added ci test run --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b52c449..a46c294 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,12 @@ jobs: with: java-version: 1.8 - - name: Build with Maven + - name: Build run: mvn -B package --file pom.xml + - name: Run Tests + run: mvn test + - name: Notify slack success if: success() env: From a5b9da83f16d26afa845830896c52550077e3b60 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Thu, 7 May 2020 21:47:25 +0300 Subject: [PATCH 17/82] Added badges --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc2d4cf..5e77d0f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,29 @@ -# Java SDK for SecureNative +

+ SecureNative Logo +

+ +

+ A Cloud-Native Security Monitoring and Protection for Modern Applications +

+

+ + Github Actions + + + + + + npm version + +

+

+ Documentation | + Quick Start | + Blog | + Chat with us on Slack! +

+
+ [SecureNative](https://www.securenative.com/) performs user monitoring by analyzing user interactions with your application and various factors such as network, devices, locations and access patterns to stop and prevent account takeover attacks. From 38b9dafce0612cec88c3d05d0f3f1326e0fd004f Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 10 May 2020 11:28:30 +0300 Subject: [PATCH 18/82] Removed based url from api manager impl --- src/main/java/com/securenative/ApiManagerImpl.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/securenative/ApiManagerImpl.java b/src/main/java/com/securenative/ApiManagerImpl.java index 958232b..9edf073 100644 --- a/src/main/java/com/securenative/ApiManagerImpl.java +++ b/src/main/java/com/securenative/ApiManagerImpl.java @@ -23,18 +23,16 @@ public ApiManagerImpl(EventManager eventManager, SecureNativeOptions options) th @Override public void track(EventOptions eventOptions) { logger.info("Track event call"); - String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.TRACK.getApiRoute()); Event event = new SDKEvent(eventOptions, this.options); - this.eventManager.sendAsync(event,requestUrl, true); + this.eventManager.sendAsync(event, ApiRoute.TRACK.getApiRoute(), true); } @Override public VerifyResult verify(EventOptions eventOptions) { logger.info("Verify event call"); - String requestUrl = String.format("%s/%s", this.options.getApiUrl(), ApiRoute.VERIFY.getApiRoute()); Event event = new SDKEvent(eventOptions, this.options); try { - return this.eventManager.sendSync(VerifyResult.class , event, requestUrl); + return this.eventManager.sendSync(VerifyResult.class , event, ApiRoute.VERIFY.getApiRoute()); } catch (Exception ex) { logger.error("Failed to call verify", ex); return this.options.getFailoverStrategy() == FailoverStrategy.FAIL_OPEN ? From 4b25ba1e010dd898d415bff4e42b46968f167cda Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 10 May 2020 11:36:20 +0300 Subject: [PATCH 19/82] Bump version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e097fe3..3556b3a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.3 + 0.3.4 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 32a7926faffe92c5d32dd611d3b8fb82576f3b6a Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 10 May 2020 16:45:15 +0300 Subject: [PATCH 20/82] Added headers sending --- .../http/SecureNativeHTTPClient.java | 11 ++++++--- .../com/securenative/utils/VersionUtils.java | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/securenative/utils/VersionUtils.java diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java index 0a09e44..0767a19 100644 --- a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -4,6 +4,7 @@ import com.securenative.exceptions.SecureNativeInvalidUriException; import com.securenative.http.HttpClient; import com.securenative.http.HttpResponse; +import com.securenative.utils.VersionUtils; import okhttp3.*; import java.io.IOException; @@ -11,8 +12,10 @@ import java.util.concurrent.TimeUnit; public class SecureNativeHTTPClient implements HttpClient { - private final String USER_AGENT_VALUE = "SecureNative-java"; - private final String SN_VERSION = "SN-Version"; + private final String AUTHORIZATION_HEADER = "Authorization"; + private final String VERSION_HEADER = "SN-Version"; + private final String USER_AGENT_HEADER = "User-Agent"; + private final String USER_AGENT_HEADER_VALUE = "SecureNative-java"; private final OkHttpClient client; private final SecureNativeOptions options; public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); @@ -26,7 +29,9 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { .addInterceptor((chain) ->{ Request request = chain.request(); Request authenticatedRequest = request.newBuilder() - .header("Authorization", options.getApiKey()).build(); + .header(USER_AGENT_HEADER, USER_AGENT_HEADER_VALUE) + .header(VERSION_HEADER, VersionUtils.getVersion()) + .header(AUTHORIZATION_HEADER, options.getApiKey()).build(); return chain.proceed(authenticatedRequest); }).build(); } diff --git a/src/main/java/com/securenative/utils/VersionUtils.java b/src/main/java/com/securenative/utils/VersionUtils.java new file mode 100644 index 0000000..7a427b2 --- /dev/null +++ b/src/main/java/com/securenative/utils/VersionUtils.java @@ -0,0 +1,24 @@ +package com.securenative.utils; + +import com.securenative.ResourceStream; +import com.securenative.ResourceStreamImpl; +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; + +public class VersionUtils { + private static ResourceStream resourceStream = new ResourceStreamImpl(); + + public static String getVersion() { + try { + MavenXpp3Reader reader = new MavenXpp3Reader(); + String POM_RESOURCE = "/META-INF/maven/com.securenative.java/pom.xml"; + Model read = reader.read(resourceStream.getInputStream(POM_RESOURCE)); + return read.getParent().getVersion(); + } catch (Exception e) { + return "unknown"; + } + } +} + + + From e631f98cdf88d3cba9e336b2449c9d2cc5073bdc Mon Sep 17 00:00:00 2001 From: alexivsn Date: Sun, 10 May 2020 16:47:50 +0300 Subject: [PATCH 21/82] Updated version to 0.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3556b3a..45d173c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.4 + 0.3.5 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 2f1eb63abadd88cc745ae780274e3c129d10acb7 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 12:25:30 +0300 Subject: [PATCH 22/82] Start automatic event persistance --- .../java/com/securenative/SecureNative.java | 7 +++++- .../com/securenative/utils/VersionTest.java | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/securenative/utils/VersionTest.java diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java index 023ab81..5787550 100644 --- a/src/main/java/com/securenative/SecureNative.java +++ b/src/main/java/com/securenative/SecureNative.java @@ -30,7 +30,12 @@ private SecureNative(SecureNativeOptions options) throws SecureNativeSDKExceptio throw new SecureNativeSDKException("You must pass your SecureNative api key"); } this.options = options; - this.apiManager = new ApiManagerImpl(new SecureNativeEventManager(new SecureNativeHTTPClient(options), options), options); + + EventManager eventManager = new SecureNativeEventManager(new SecureNativeHTTPClient(options), options); + if(options.getAutoSend()){ + eventManager.startEventsPersist(); + } + this.apiManager = new ApiManagerImpl(eventManager, options); Logger.initLogger(options.getLogLevel()); } diff --git a/src/test/java/com/securenative/utils/VersionTest.java b/src/test/java/com/securenative/utils/VersionTest.java new file mode 100644 index 0000000..f7924a0 --- /dev/null +++ b/src/test/java/com/securenative/utils/VersionTest.java @@ -0,0 +1,25 @@ +package com.securenative.utils; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.Enumeration; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +public class VersionTest { + + @Test + public void testManifest() throws IOException { + URL res = org.junit.Assert.class.getResource(org.junit.Assert.class.getSimpleName() + ".class"); + JarURLConnection conn = (JarURLConnection) res.openConnection(); + Manifest mf = conn.getManifest(); + + Attributes atts = mf.getMainAttributes(); + for (Object v : atts.values()) { + System.out.println(v); + } + } +} From 87655e125b66ad77866718dbb3bae040315153d2 Mon Sep 17 00:00:00 2001 From: alexivsn <45174009+alexivsn@users.noreply.github.com> Date: Mon, 11 May 2020 12:38:40 +0300 Subject: [PATCH 23/82] Bump version number to 0.3.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 45d173c..40cca07 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.5 + 0.3.6 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} @@ -282,4 +282,4 @@ 1.6 0.2.3 - \ No newline at end of file + From 018086615b21c316cc6925cbcc17c2eb5c982820 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 14:17:41 +0300 Subject: [PATCH 24/82] Added publish to maven workflow --- .github/workflows/publish.yml | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..570e34b --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,63 @@ +name: Publish + +on: + release: + types: [created] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Notify Starting + if: success() + id: slack # IMPORTANT: reference this step ID value in future Slack steps + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + channel: github-actions + status: STARTING + color: warning + + - uses: actions/checkout@v2 + - name: Set up Maven Central Repository + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + + - name: Build + run: mvn -B package --file pom.xml + + - name: Run Tests + run: mvn test + + - name: Publish package + run: mvn -B deploy + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + + - name: Notify slack success + if: success() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: SUCCESS + color: good + + - name: Notify slack fail + if: failure() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: FAILED + color: danger \ No newline at end of file From c6293909864eecb5e8ebbdb7ceec98d3c71ca67f Mon Sep 17 00:00:00 2001 From: alexivsn <45174009+alexivsn@users.noreply.github.com> Date: Mon, 11 May 2020 14:32:17 +0300 Subject: [PATCH 25/82] Test deployment --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 40cca07..d6097f9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.6 + 0.3.7 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 3d28350ca1466dc89fbc3915a209ca078212e83e Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 14:43:12 +0300 Subject: [PATCH 26/82] Updated publish with gpg --- .github/workflows/publish.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 570e34b..cea2dba 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,11 +34,13 @@ jobs: - name: Run Tests run: mvn test - - name: Publish package - run: mvn -B deploy - env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + - name: Release Maven package + uses: samuelmeuli/action-maven-publish@v1 + with: + gpg_private_key: ${{ secrets.gpg_private_key }} + gpg_passphrase: ${{ secrets.gpg_passphrase }} + nexus_username: ${{ secrets.nexus_username }} + nexus_password: ${{ secrets.nexus_password }} - name: Notify slack success if: success() @@ -50,7 +52,7 @@ jobs: channel: github-actions status: SUCCESS color: good - + - name: Notify slack fail if: failure() env: From a9ee30efadd2aa7a550bf00c68b8dca758bca9a9 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 15:07:00 +0300 Subject: [PATCH 27/82] Updated pom --- pom.xml | 80 +++++++++++++++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/pom.xml b/pom.xml index 45d173c..f899513 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ + ossrh https://oss.sonatype.org/content/repositories/snapshots @@ -50,17 +51,37 @@ deploy + - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins maven-gpg-plugin @@ -72,6 +93,13 @@ sign + + + + --pinentry-mode + loopback + + @@ -189,7 +217,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.7 + 1.6.8 true ossrh @@ -197,38 +225,6 @@ true - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.1.1 - - - - ${java.home}/bin/javadoc - false - - - - attach-javadocs - - jar - - - - org.apache.maven.plugins maven-gpg-plugin From b7fcd11aac4bea4b0d522fa78cc51fbf40b939ef Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 17:13:20 +0300 Subject: [PATCH 28/82] Added coverage --- .github/workflows/build.yml | 65 +++++++++++++++++++++++++++++++++++++ pom.xml | 19 +++++++++++ 2 files changed, 84 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..e37fb1f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,65 @@ +name: Build + +on: + push: + branches: + - master + - dev + - dev-* + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Notify slack success + if: success() + id: slack # IMPORTANT: reference this step ID value in future Slack steps + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + channel: github-actions + status: STARTING + color: warning + + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Build + run: mvn -B package --file pom.xml + + - name: Run Tests + run: mvn test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + name: codecov-umbrella + fail_ci_if_error: true + + - name: Notify slack success + if: success() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: SUCCESS + color: good + + - name: Notify slack fail + if: failure() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: voxmedia/github-action-slack-notify-build@v1.1.1 + with: + message_id: ${{ steps.slack.outputs.message_id }} + channel: github-actions + status: FAILED + color: danger diff --git a/pom.xml b/pom.xml index f899513..0ced581 100644 --- a/pom.xml +++ b/pom.xml @@ -268,6 +268,25 @@ false + + org.jacoco + jacoco-maven-plugin + 0.8.3 + + + + prepare-agent + + + + report + test + + report + + + + From 378fc57a97ecc56a4ee6219039159d46dbd504ec Mon Sep 17 00:00:00 2001 From: alexivsn Date: Mon, 11 May 2020 17:18:41 +0300 Subject: [PATCH 29/82] Updated version to 0.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0ced581..73df741 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.3.5 + 0.4.1 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 9826bf4bda9a25e75085d365d7e6af962ff410a3 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 26 May 2020 16:37:31 +0300 Subject: [PATCH 30/82] Downgraded okhttp dependency --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 73df741..9494905 100644 --- a/pom.xml +++ b/pom.xml @@ -130,10 +130,10 @@ slf4j-api 1.7.12
- + com.squareup.okhttp3 okhttp - 4.0.0 + 3.13.1 org.mockito From 43e1d2485b6596ee63afe7f0631f239b37e23c91 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 26 May 2020 16:43:19 +0300 Subject: [PATCH 31/82] Switched req arguments --- src/main/java/com/securenative/http/SecureNativeHTTPClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java index 0767a19..ab2f6b7 100644 --- a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -39,7 +39,7 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { @Override public HttpResponse post(String path, String json) throws IOException { - RequestBody body = RequestBody.create(json, JSON); + RequestBody body = RequestBody.create(JSON, json); String url = String.format("%s/%s", this.options.getApiUrl(), path); From 08f1e9539da7038d0bdc88b305afdb3f50d9a73d Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 26 May 2020 18:04:10 +0300 Subject: [PATCH 32/82] Updated okhttp dependency --- pom.xml | 2 +- .../com/securenative/http/SecureNativeHTTPClient.java | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index efe4096..3484878 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ com.squareup.okhttp3 okhttp - 3.13.1 + 4.1.0 org.mockito diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java index ab2f6b7..aed896d 100644 --- a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -1,9 +1,6 @@ package com.securenative.http; import com.securenative.config.SecureNativeOptions; -import com.securenative.exceptions.SecureNativeInvalidUriException; -import com.securenative.http.HttpClient; -import com.securenative.http.HttpResponse; import com.securenative.utils.VersionUtils; import okhttp3.*; @@ -18,7 +15,7 @@ public class SecureNativeHTTPClient implements HttpClient { private final String USER_AGENT_HEADER_VALUE = "SecureNative-java"; private final OkHttpClient client; private final SecureNativeOptions options; - public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + public static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8"); public SecureNativeHTTPClient(SecureNativeOptions options) { this.options = options; @@ -38,9 +35,9 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { @Override - public HttpResponse post(String path, String json) throws IOException { - RequestBody body = RequestBody.create(JSON, json); - + public HttpResponse post(String path, String payload) throws IOException { + RequestBody body = RequestBody.create(payload, JSON_MEDIA_TYPE); + String url = String.format("%s/%s", this.options.getApiUrl(), path); Request request = new Request.Builder() From fc1c1cc851408cb83075567f63c71e537b34313f Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 26 May 2020 18:13:02 +0300 Subject: [PATCH 33/82] Updated test timeout --- .../java/com/securenative/config/ConfigurationManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 4459151..a2f5a4f 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -26,7 +26,7 @@ private static void setEnv(String name, String val) throws ReflectiveOperationEx @Test @Order(1) - @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should parse config file correctly") public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { String config = String.join(System.getProperty("line.separator"), From a55d86e5f052aee48efce36a0fa00c1f900e3ba2 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 26 May 2020 18:13:26 +0300 Subject: [PATCH 34/82] Updated version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3484878..65827ec 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.2 + 0.4.3 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 91ff427bef3f8f20dea504d9890e901f327f4006 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Thu, 28 May 2020 15:21:39 +0300 Subject: [PATCH 35/82] Fix okhttp and version extraction --- pom.xml | 14 ++++-- .../http/SecureNativeHTTPClient.java | 2 +- .../com/securenative/utils/VersionUtils.java | 44 ++++++++++++++++--- .../com/securenative/utils/VersionTest.java | 38 ++++++++++------ 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/pom.xml b/pom.xml index 65827ec..56c3bae 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.3 + 0.4.4 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} @@ -133,7 +133,7 @@ com.squareup.okhttp3 okhttp - 4.1.0 + 3.14.8 org.mockito @@ -156,7 +156,7 @@ com.squareup.okhttp3 mockwebserver - 4.0.0 + 3.14.8 test @@ -200,6 +200,14 @@ org.apache.maven.plugins maven-jar-plugin 2.4 + + + + true + true + + + maven-deploy-plugin diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java index aed896d..b7a8516 100644 --- a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -36,7 +36,7 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { @Override public HttpResponse post(String path, String payload) throws IOException { - RequestBody body = RequestBody.create(payload, JSON_MEDIA_TYPE); + RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, payload); String url = String.format("%s/%s", this.options.getApiUrl(), path); diff --git a/src/main/java/com/securenative/utils/VersionUtils.java b/src/main/java/com/securenative/utils/VersionUtils.java index 7a427b2..3d75343 100644 --- a/src/main/java/com/securenative/utils/VersionUtils.java +++ b/src/main/java/com/securenative/utils/VersionUtils.java @@ -2,21 +2,53 @@ import com.securenative.ResourceStream; import com.securenative.ResourceStreamImpl; +import com.securenative.SecureNative; +import com.securenative.config.ConfigurationManager; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import java.io.InputStream; +import java.util.Properties; + public class VersionUtils { private static ResourceStream resourceStream = new ResourceStreamImpl(); - public static String getVersion() { + public static void setResourceStream(ResourceStream resourceStream) { + VersionUtils.resourceStream = resourceStream; + } + + public static synchronized String getVersion() { + String version = null; + + // try to load from maven properties first try { - MavenXpp3Reader reader = new MavenXpp3Reader(); - String POM_RESOURCE = "/META-INF/maven/com.securenative.java/pom.xml"; - Model read = reader.read(resourceStream.getInputStream(POM_RESOURCE)); - return read.getParent().getVersion(); + Properties p = new Properties(); + InputStream is = resourceStream.getInputStream("/META-INF/maven/com.securenative.java/securenative-java/pom.properties"); + if (is != null) { + p.load(is); + version = p.getProperty("version", ""); + } } catch (Exception e) { - return "unknown"; + // ignore } + + // fallback to using Java API + if (version == null) { + Package aPackage = VersionUtils.class.getPackage(); + if (aPackage != null) { + version = aPackage.getImplementationVersion(); + if (version == null) { + version = aPackage.getSpecificationVersion(); + } + } + } + + if (version == null) { + // we could not compute the version so use a blank + version = "unknown"; + } + + return version; } } diff --git a/src/test/java/com/securenative/utils/VersionTest.java b/src/test/java/com/securenative/utils/VersionTest.java index f7924a0..d5c83fc 100644 --- a/src/test/java/com/securenative/utils/VersionTest.java +++ b/src/test/java/com/securenative/utils/VersionTest.java @@ -1,25 +1,35 @@ package com.securenative.utils; +import com.securenative.ResourceStreamImpl; +import com.securenative.config.ConfigurationManager; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.net.JarURLConnection; -import java.net.URL; -import java.util.Enumeration; -import java.util.jar.Attributes; -import java.util.jar.Manifest; +import java.io.InputStream; + +import static org.assertj.core.api.Assertions.assertThat; public class VersionTest { @Test - public void testManifest() throws IOException { - URL res = org.junit.Assert.class.getResource(org.junit.Assert.class.getSimpleName() + ".class"); - JarURLConnection conn = (JarURLConnection) res.openConnection(); - Manifest mf = conn.getManifest(); - - Attributes atts = mf.getMainAttributes(); - for (Object v : atts.values()) { - System.out.println(v); - } + public void testVersionExtraction() throws IOException { + + String props = String.join(System.getProperty("line.separator"), + "version=1.0.0", + "groupId=com.securenative.java", + "artifactId=securenative-java"); + + InputStream inputStream = new ByteArrayInputStream(props.getBytes()); + ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); + Mockito.when(resourceStream.getInputStream("/META-INF/maven/com.securenative.java/securenative-java/pom.properties")).thenReturn(inputStream); + + VersionUtils.setResourceStream(resourceStream); + + assertThat(VersionUtils.getVersion()).isEqualTo("1.0.0"); + + // restore resource stream + VersionUtils.setResourceStream(new ResourceStreamImpl()); } } From e4d23d2018a3d8e88cca677958b2b40c08915532 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 15 Jul 2020 11:09:19 +0300 Subject: [PATCH 36/82] Add phone field to user traits --- README.md | 6 +++--- pom.xml | 2 +- .../com/securenative/EventOptionsBuilder.java | 5 +++++ .../com/securenative/models/UserTraits.java | 19 ++++++++++++++++++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5e77d0f..5fb1a2b 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ SecureNativeContext context = SecureNative.contextBuilder() EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL") + .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -121,7 +121,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL") + .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -148,7 +148,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL") + .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") diff --git a/pom.xml b/pom.xml index 56c3bae..07aea16 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.4 + 0.4.5 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index bb195f8..9cf69ea 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -47,6 +47,11 @@ public EventOptionsBuilder userTraits(String name, String email, Date createdAt) return this; } + public EventOptionsBuilder userTraits(String name, String email, String phone) { + this.eventOptions.setUserTraits(new UserTraits(name, email, phone)); + return this; + } + public EventOptionsBuilder context(SecureNativeContext context) { this.eventOptions.setContext(context); return this; diff --git a/src/main/java/com/securenative/models/UserTraits.java b/src/main/java/com/securenative/models/UserTraits.java index 7e9493d..9269068 100644 --- a/src/main/java/com/securenative/models/UserTraits.java +++ b/src/main/java/com/securenative/models/UserTraits.java @@ -7,19 +7,28 @@ public class UserTraits { private String name; private String email; + private String phone; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") private Date createdAt; public UserTraits(String name) { this(name, null, null); } + public UserTraits(String name, String email) { this(name, email, null); } - public UserTraits(String name, String email, Date createdAt) { + public UserTraits(String name, String email, String phone) { + this.name = name; + this.email = email; + this.phone = phone; + } + + public UserTraits(String name, String email, String phone, Date createdAt) { this.name = name; this.email = email; + this.phone = phone; this.createdAt = createdAt; } @@ -46,4 +55,12 @@ public Date getCreatedAt() { public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } } From afe3c7f0c12ba461cab0c35ea99a0251c2f10b5a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 15 Jul 2020 11:17:22 +0300 Subject: [PATCH 37/82] Add phone field to user traits --- src/main/java/com/securenative/EventOptionsBuilder.java | 5 +++++ src/main/java/com/securenative/models/UserTraits.java | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index 9cf69ea..408f49c 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -42,6 +42,11 @@ public EventOptionsBuilder userTraits(String name, String email) { return this; } + public EventOptionsBuilder userTraits(String name, String email, String phone, Date createdAt) { + this.eventOptions.setUserTraits(new UserTraits(name, email, phone, createdAt)); + return this; + } + public EventOptionsBuilder userTraits(String name, String email, Date createdAt) { this.eventOptions.setUserTraits(new UserTraits(name, email, createdAt)); return this; diff --git a/src/main/java/com/securenative/models/UserTraits.java b/src/main/java/com/securenative/models/UserTraits.java index 9269068..b45b681 100644 --- a/src/main/java/com/securenative/models/UserTraits.java +++ b/src/main/java/com/securenative/models/UserTraits.java @@ -25,6 +25,12 @@ public UserTraits(String name, String email, String phone) { this.phone = phone; } + public UserTraits(String name, String email, Date createdAt) { + this.name = name; + this.email = email; + this.createdAt = createdAt; + } + public UserTraits(String name, String email, String phone, Date createdAt) { this.name = name; this.email = email; From 15825138ec766043173f071162cc568cfa8060c9 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 15 Jul 2020 11:26:44 +0300 Subject: [PATCH 38/82] Add phone field to user traits --- src/main/java/com/securenative/EventOptionsBuilder.java | 5 ----- src/main/java/com/securenative/models/UserTraits.java | 6 ------ 2 files changed, 11 deletions(-) diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index 408f49c..0994c84 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -47,11 +47,6 @@ public EventOptionsBuilder userTraits(String name, String email, String phone, D return this; } - public EventOptionsBuilder userTraits(String name, String email, Date createdAt) { - this.eventOptions.setUserTraits(new UserTraits(name, email, createdAt)); - return this; - } - public EventOptionsBuilder userTraits(String name, String email, String phone) { this.eventOptions.setUserTraits(new UserTraits(name, email, phone)); return this; diff --git a/src/main/java/com/securenative/models/UserTraits.java b/src/main/java/com/securenative/models/UserTraits.java index b45b681..9269068 100644 --- a/src/main/java/com/securenative/models/UserTraits.java +++ b/src/main/java/com/securenative/models/UserTraits.java @@ -25,12 +25,6 @@ public UserTraits(String name, String email, String phone) { this.phone = phone; } - public UserTraits(String name, String email, Date createdAt) { - this.name = name; - this.email = email; - this.createdAt = createdAt; - } - public UserTraits(String name, String email, String phone, Date createdAt) { this.name = name; this.email = email; From 30feff8410786eabb3dd94d6a8bde93b96e43066 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 19 Jul 2020 10:42:12 +0300 Subject: [PATCH 39/82] Run github actions on multiple os --- .github/workflows/build.yml | 5 ++++- .github/workflows/ci.yml | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e37fb1f..da82754 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,10 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] steps: - name: Notify slack success if: success() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a46c294..cde29a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,10 @@ on: jobs: ci: - - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] steps: - name: Notify slack success if: success() From 1d3bb504800bb771a184874900047e31fe0cb745 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 19 Jul 2020 10:46:15 +0300 Subject: [PATCH 40/82] Run github actions on multiple os --- .github/workflows/build.yml | 6 +++--- .github/workflows/ci.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da82754..a357d5f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,9 +10,9 @@ on: jobs: build: runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] steps: - name: Notify slack success if: success() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cde29a9..8b74eeb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,9 @@ on: jobs: ci: runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] steps: - name: Notify slack success if: success() From 71f4f9264909a31873f030ae663aa366e0c06361 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:37:31 +0300 Subject: [PATCH 41/82] Disable windows unitest compitability --- .../java/com/securenative/config/ConfigurationManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index a2f5a4f..0c310d0 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -167,6 +167,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Order(6) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") + @DisabledOnOs(WINDOWS) public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); @@ -205,6 +206,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, @Order(7) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should overwrite env variables with vales from config file") + @DisabledOnOs(WINDOWS) public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", From 4b5ec32622c8f408550a941f447cec69bdb7a13a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:42:53 +0300 Subject: [PATCH 42/82] Disable windows unitest compitability --- .../com/securenative/config/ConfigurationManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 0c310d0..869bf96 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -167,7 +167,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Order(6) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") - @DisabledOnOs(WINDOWS) + @DisabledOnOs({OS.WINDOWS}) public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); @@ -206,7 +206,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, @Order(7) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should overwrite env variables with vales from config file") - @DisabledOnOs(WINDOWS) + @DisabledOnOs({OS.WINDOWS}) public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", From c39e8c233d730e17913caa9bdb0624c3b326544e Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:48:01 +0300 Subject: [PATCH 43/82] Disable windows unitest compitability --- .../securenative/config/ConfigurationManagerTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 869bf96..5806b63 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -14,6 +14,12 @@ import static org.assertj.core.api.Assertions.assertThat; +public class NotRunningOnWindows implements IgnoreCondition { + public boolean isSatisfied() { + return !System.getProperty("os.name").startsWith("Windows"); + } +} + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ConfigurationManagerTest { @SuppressWarnings({ "unchecked" }) @@ -167,7 +173,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Order(6) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") - @DisabledOnOs({OS.WINDOWS}) + @ConditionalIgnore(condition = NotRunningOnWindows.class) public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); @@ -206,7 +212,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, @Order(7) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should overwrite env variables with vales from config file") - @DisabledOnOs({OS.WINDOWS}) + @ConditionalIgnore(condition = NotRunningOnWindows.class) public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", From d349831ab060434adbcbd4e3418e2eabc466ad35 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:50:05 +0300 Subject: [PATCH 44/82] Disable windows unitest compitability --- .../java/com/securenative/config/ConfigurationManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 5806b63..8e601cb 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class NotRunningOnWindows implements IgnoreCondition { +class NotRunningOnWindows implements IgnoreCondition { public boolean isSatisfied() { return !System.getProperty("os.name").startsWith("Windows"); } From 99d14d70b8e724ba3a0981eb9899c16a2d48bef0 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:52:12 +0300 Subject: [PATCH 45/82] Disable windows unitest compitability --- .../java/com/securenative/config/ConfigurationManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 8e601cb..638ac34 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -4,6 +4,7 @@ import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; import org.junit.jupiter.api.*; +import org.junit.Ignore; import org.mockito.Mockito; import java.io.ByteArrayInputStream; From 88f365ae8660b5f9121d699f8ef22fb5b2d92e25 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:56:58 +0300 Subject: [PATCH 46/82] Disable windows unitest compitability --- .../config/ConfigurationManagerTest.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 638ac34..5d0f81c 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -4,7 +4,7 @@ import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; import org.junit.jupiter.api.*; -import org.junit.Ignore; +import org.junit.*; import org.mockito.Mockito; import java.io.ByteArrayInputStream; @@ -15,12 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; -class NotRunningOnWindows implements IgnoreCondition { - public boolean isSatisfied() { - return !System.getProperty("os.name").startsWith("Windows"); - } -} - @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ConfigurationManagerTest { @SuppressWarnings({ "unchecked" }) @@ -174,7 +168,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Order(6) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") - @ConditionalIgnore(condition = NotRunningOnWindows.class) + @DisabledOnOs(OS.WINDOWS) public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); @@ -213,7 +207,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, @Order(7) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should overwrite env variables with vales from config file") - @ConditionalIgnore(condition = NotRunningOnWindows.class) + @DisabledOnOs(OS.WINDOWS) public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", From 6c7af2ee4f7ec66d95ee6ed9e143e8cbb5b02561 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 15:58:54 +0300 Subject: [PATCH 47/82] Disable windows unitest compitability --- .../java/com/securenative/config/ConfigurationManagerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 5d0f81c..ea370e8 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -4,7 +4,6 @@ import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; import org.junit.jupiter.api.*; -import org.junit.*; import org.mockito.Mockito; import java.io.ByteArrayInputStream; From 0f8a381edac88e288f8443279f005ea2841510d6 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 16:04:07 +0300 Subject: [PATCH 48/82] Disable windows unitest compitability --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a357d5f..ef5120b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [macos-latest, ubuntu-latest] steps: - name: Notify slack success if: success() From ba55760093e07b68823bfa64f95c5d209f502886 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 26 Jul 2020 16:05:44 +0300 Subject: [PATCH 49/82] Disable windows unitest compitability --- .github/workflows/ci.yml | 2 +- .../java/com/securenative/config/ConfigurationManagerTest.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b74eeb..f688093 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [macos-latest, ubuntu-latest] steps: - name: Notify slack success if: success() diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index ea370e8..a2f5a4f 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -167,7 +167,6 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { @Order(6) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should get config via env variables") - @DisabledOnOs(OS.WINDOWS) public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, ReflectiveOperationException { setEnv("SECURENATIVE_API_KEY", "SOME_ENV_API_KEY"); setEnv("SECURENATIVE_API_URL", "SOME_API_URL"); @@ -206,7 +205,6 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, @Order(7) @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should overwrite env variables with vales from config file") - @DisabledOnOs(OS.WINDOWS) public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigException, ReflectiveOperationException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_API_KEY=API_KEY_FROM_FILE", From eeae3ead0588a45f8a7b53b1dcef326a6aaf2931 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 12:17:00 +0300 Subject: [PATCH 50/82] Fix context builder factory names --- README.md | 2 +- pom.xml | 2 +- .../context/SecureNativeContextBuilder.java | 28 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5fb1a2b..c2210bf 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ When using Maven, add the following dependency to your `pom.xml` file: ```xml com.securenative.java - sdk-base + securenative-java LATEST ``` diff --git a/pom.xml b/pom.xml index 07aea16..6cc71d7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.5 + 0.4.6 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java index 5dbeb11..b329bc9 100644 --- a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -13,37 +13,37 @@ private SecureNativeContextBuilder() { this.context = new SecureNativeContext(); } - public SecureNativeContextBuilder clientToken(String clientToken) { + public SecureNativeContextBuilder withClientToken(String clientToken) { this.context.setClientToken(clientToken); return this; } - public SecureNativeContextBuilder ip(String ip) { + public SecureNativeContextBuilder withIp(String ip) { this.context.setIp(ip); return this; } - public SecureNativeContextBuilder remoteIp(String remoteIp) { + public SecureNativeContextBuilder withRemoteIp(String remoteIp) { this.context.setRemoteIp(remoteIp); return this; } - public SecureNativeContextBuilder headers(Map headers) { + public SecureNativeContextBuilder withHeaders(Map headers) { this.context.setHeaders(headers); return this; } - public SecureNativeContextBuilder url(String url) { + public SecureNativeContextBuilder withUrl(String url) { this.context.setUrl(url); return this; } - public SecureNativeContextBuilder method(String method) { + public SecureNativeContextBuilder withMethod(String method) { this.context.setMethod(method); return this; } - public SecureNativeContextBuilder body(String body) { + public SecureNativeContextBuilder withBody(String body) { this.context.setBody(body); return this; } @@ -61,13 +61,13 @@ public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletReque } return new SecureNativeContextBuilder() - .url(request.getRequestURI()) - .method(request.getMethod()) - .headers(headers) - .clientToken(clientToken) - .ip(RequestUtils.getClientIpFromRequest(request, headers)) - .remoteIp(RequestUtils.getRemoteIpFromRequest(request)) - .body(null); + .withUrl(request.getRequestURI()) + .withMethod(request.getMethod()) + .withHeaders(headers) + .withClientToken(clientToken) + .withIp(RequestUtils.getClientIpFromRequest(request, headers)) + .withRemoteIp(RequestUtils.getRemoteIpFromRequest(request)) + .withBody(null); } public SecureNativeContext build(){ From 4b93c540d484512a2620d10d6426acd46db2dad6 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 12:34:17 +0300 Subject: [PATCH 51/82] Fix tests --- .../context/SecureNativeContextBuilderTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java index 2807de0..04a480b 100644 --- a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -83,13 +83,13 @@ public void createDefaultContextBuilderTest() { public void createCustomContextWithContextBuilderTest() { SecureNativeContext context = SecureNativeContextBuilder .defaultContextBuilder() - .url("/some-url") - .clientToken("SECRET_TOKEN") - .ip("10.0.0.0") - .body("{ \"name\": \"YOUR_NAME\" }") - .method("Get") - .remoteIp("10.0.0.1") - .headers(Maps.defaultBuilder() + .withUrl("/some-url") + .withClientToken("SECRET_TOKEN") + .withIp("10.0.0.0") + .withBody("{ \"name\": \"YOUR_NAME\" }") + .withMethod("Get") + .withRemoteIp("10.0.0.1") + .withHeaders(Maps.defaultBuilder() .put("header1", "value1") .build()) .build(); From bf91e563ffc32b875df511b0283c56bc8fa6e2d2 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 12:39:41 +0300 Subject: [PATCH 52/82] Fix tests --- pom.xml.asc | 11 ----------- .../java/com/securenative/ApiManagerImplTest.java | 6 +++--- 2 files changed, 3 insertions(+), 14 deletions(-) delete mode 100644 pom.xml.asc diff --git a/pom.xml.asc b/pom.xml.asc deleted file mode 100644 index 79ee87b..0000000 --- a/pom.xml.asc +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQEzBAABCAAdFiEE3Et7fS4h12t+F7BE7tXV6OHJmUQFAl550F8ACgkQ7tXV6OHJ -mURXqgf9Edq8gvhESTwstYoZnjegKvSBVaz7lBU6XFfp/3DuRwVr1xICvdiEIROZ -LOCcXcrLqnLproWrIA0Cd3ZeDPu1xwL9HRAD10f5v03jrZgszxIQxV/besphhAuf -07lncPD/OMoVoAhQLOOCTZEYAOyzsb6H9BT4wEr1SYb/GUoIxC5471TYYe/MJ8+b -o0bxRZiR2lX8engsChkc9r1I0sPkkFIITw/NKlbeZdRemdQuH9cLIZyMR1h+C99a -2O1uSXS/h2Rq+SbUh8HQ8VtMPNHsGPQpVdCa4JrA6Z9ETj68PNUraZMfAYU5XMQg -yQKs1LbCgdUAX7UtNhYXiQZa48udug== -=Ilre ------END PGP SIGNATURE----- diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java index a942061..65b9f4a 100644 --- a/src/test/java/com/securenative/ApiManagerImplTest.java +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -35,9 +35,9 @@ public class ApiManagerImplTest extends HTTPServerMock { public ApiManagerImplTest() throws SecureNativeInvalidOptionsException { // init default event for tests SecureNativeContext context = SecureNative.contextBuilder() - .ip("127.0.0.1") - .clientToken("SECURED_CLIENT_TOKEN") - .headers(Maps.defaultBuilder() + .withIp("127.0.0.1") + .withClientToken("SECURED_CLIENT_TOKEN") + .withHeaders(Maps.defaultBuilder() .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") .build()) .build(); From bd93c6b57d05b1b2d9875c615f9c2c1aad20ef7a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 12:41:56 +0300 Subject: [PATCH 53/82] Fix tests --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef5120b..80bfbd5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest] + os: [ubuntu-latest] steps: - name: Notify slack success if: success() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f688093..395c068 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest] + os: [ubuntu-latest] steps: - name: Notify slack success if: success() From 10d44a447bf4c7a2bb10a57aaefc7d066bed58f8 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 13:32:53 +0300 Subject: [PATCH 54/82] A dd path support and code cleanup --- README.md | 10 +++--- .../java/com/securenative/ApiManager.java | 1 + .../java/com/securenative/ApiManagerImpl.java | 4 +-- .../java/com/securenative/EventManager.java | 4 ++- .../com/securenative/EventOptionsBuilder.java | 8 ++--- src/main/java/com/securenative/Logger.java | 20 ++++++----- .../java/com/securenative/ResourceStream.java | 1 + .../java/com/securenative/SecureNative.java | 19 +++++++---- .../SecureNativeEventManager.java | 28 +++++++++------ .../config/ConfigurationManager.java | 34 ++++++++++++------- .../SecureNativeConfigurationBuilder.java | 3 +- .../context/SecureNativeContext.java | 5 +-- .../context/SecureNativeContextBuilder.java | 8 ++--- .../java/com/securenative/enums/ApiRoute.java | 18 +++++----- .../securenative/enums/FailoverStrategy.java | 5 ++- .../com/securenative/enums/RiskLevel.java | 2 +- .../com/securenative/http/HttpClient.java | 1 - .../com/securenative/http/HttpResponse.java | 6 ++-- .../http/SecureNativeHTTPClient.java | 22 ++++++------ .../com/securenative/models/ClientToken.java | 4 +-- .../java/com/securenative/models/Event.java | 5 +-- .../com/securenative/models/EventOptions.java | 8 +++-- .../securenative/models/RequestContext.java | 5 +-- .../com/securenative/models/SDKEvent.java | 27 ++++++++------- .../com/securenative/utils/DateUtils.java | 1 + .../securenative/utils/EncryptionUtils.java | 17 +++++----- .../java/com/securenative/utils/IPUtils.java | 4 +-- .../com/securenative/utils/RequestUtils.java | 28 +++++++-------- .../securenative/utils/SignatureUtils.java | 6 ++-- .../java/com/securenative/utils/Utils.java | 7 ++-- .../com/securenative/utils/VersionUtils.java | 4 --- .../com/securenative/ApiManagerImplTest.java | 25 +++++++------- .../com/securenative/EventManagerTest.java | 34 ++++++++++--------- .../com/securenative/SecureNativeTest.java | 29 ++++++++-------- .../config/ConfigurationManagerTest.java | 28 +++++++-------- .../SecureNativeContextBuilderTest.java | 26 +++++++------- .../http/SecureNativeHTTPClientTest.java | 5 +-- .../utils/EncryptionUtilsTest.java | 14 ++++---- .../com/securenative/utils/VersionTest.java | 5 ++- 39 files changed, 258 insertions(+), 223 deletions(-) diff --git a/README.md b/README.md index c2210bf..0d6fa82 100644 --- a/README.md +++ b/README.md @@ -140,8 +140,8 @@ public void track(HttpServletRequest request, HttpServletResponse response) { **Example** ```java -@RequestMapping("/track") -public void track(HttpServletRequest request, HttpServletResponse response) { +@RequestMapping("/verify") +public void verify(HttpServletRequest request, HttpServletResponse response) { SecureNativeContext context = SecureNative.contextBuilder() .fromHttpServletRequest(request) .build(); @@ -159,9 +159,9 @@ public void track(HttpServletRequest request, HttpServletResponse response) { .build(); VerifyResult verifyResult = secureNative.verify(eventOptions); - verifyResult.getRiskLevel() // Low, Medium, High - verifyResult.score() // Risk score: 0 -1 (0 - Very Low, 1 - Very High) - verifyResult.getTriggers() // ["TOR", "New IP", "New City"] + verifyResult.getRiskLevel(); // Low, Medium, High + verifyResult.score(); // Risk score: 0 -1 (0 - Very Low, 1 - Very High) + verifyResult.getTriggers(); // ["TOR", "New IP", "New City"] } ``` diff --git a/src/main/java/com/securenative/ApiManager.java b/src/main/java/com/securenative/ApiManager.java index d587243..8255ed2 100644 --- a/src/main/java/com/securenative/ApiManager.java +++ b/src/main/java/com/securenative/ApiManager.java @@ -5,5 +5,6 @@ public interface ApiManager { void track(EventOptions eventOptions); + VerifyResult verify(EventOptions eventOptions); } diff --git a/src/main/java/com/securenative/ApiManagerImpl.java b/src/main/java/com/securenative/ApiManagerImpl.java index 9edf073..1cae4a2 100644 --- a/src/main/java/com/securenative/ApiManagerImpl.java +++ b/src/main/java/com/securenative/ApiManagerImpl.java @@ -7,8 +7,8 @@ import com.securenative.exceptions.SecureNativeSDKException; import com.securenative.models.Event; import com.securenative.models.EventOptions; -import com.securenative.models.VerifyResult; import com.securenative.models.SDKEvent; +import com.securenative.models.VerifyResult; public class ApiManagerImpl implements ApiManager { private final EventManager eventManager; @@ -32,7 +32,7 @@ public VerifyResult verify(EventOptions eventOptions) { logger.info("Verify event call"); Event event = new SDKEvent(eventOptions, this.options); try { - return this.eventManager.sendSync(VerifyResult.class , event, ApiRoute.VERIFY.getApiRoute()); + return this.eventManager.sendSync(VerifyResult.class, event, ApiRoute.VERIFY.getApiRoute()); } catch (Exception ex) { logger.error("Failed to call verify", ex); return this.options.getFailoverStrategy() == FailoverStrategy.FAIL_OPEN ? diff --git a/src/main/java/com/securenative/EventManager.java b/src/main/java/com/securenative/EventManager.java index 684c12e..a81d301 100644 --- a/src/main/java/com/securenative/EventManager.java +++ b/src/main/java/com/securenative/EventManager.java @@ -1,6 +1,5 @@ package com.securenative; -import com.securenative.exceptions.SecureNativeInvalidUriException; import com.securenative.exceptions.SecureNativeParseException; import com.securenative.models.Event; @@ -8,7 +7,10 @@ public interface EventManager { T sendSync(Class clazz, Event event, String url) throws IOException, SecureNativeParseException; + void sendAsync(Event event, String url, Boolean retry); + void startEventsPersist(); + void stopEventsPersist(); } diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index 0994c84..63e8b65 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -2,9 +2,9 @@ import com.securenative.context.SecureNativeContext; +import com.securenative.enums.EventTypes; import com.securenative.exceptions.SecureNativeInvalidOptionsException; import com.securenative.models.EventOptions; -import com.securenative.enums.EventTypes; import com.securenative.models.UserTraits; import java.util.Date; @@ -15,11 +15,11 @@ public class EventOptionsBuilder { private static final Logger logger = Logger.getLogger(EventOptionsBuilder.class); private final EventOptions eventOptions; - public static EventOptionsBuilder builder(String eventType){ + public static EventOptionsBuilder builder(String eventType) { return new EventOptionsBuilder(eventType); } - public static EventOptionsBuilder builder(EventTypes eventType){ + public static EventOptionsBuilder builder(EventTypes eventType) { return new EventOptionsBuilder(eventType.getType()); } @@ -68,7 +68,7 @@ public EventOptionsBuilder timestamp(Date timestamp) { } public EventOptions build() throws SecureNativeInvalidOptionsException { - if(this.eventOptions.getProperties().size() > MAX_PROPERTIES_SIZE){ + if (this.eventOptions.getProperties().size() > MAX_PROPERTIES_SIZE) { throw new SecureNativeInvalidOptionsException(String.format("You can have only up to %d custom properties", MAX_PROPERTIES_SIZE)); } return this.eventOptions; diff --git a/src/main/java/com/securenative/Logger.java b/src/main/java/com/securenative/Logger.java index 2f06807..ed67157 100644 --- a/src/main/java/com/securenative/Logger.java +++ b/src/main/java/com/securenative/Logger.java @@ -24,9 +24,13 @@ public String toString() { interface ILogger { void trace(String var1, Object... var2); + void debug(String var1, Object... var2); + void info(String var1, Object... var2); + void warn(String var1, Object... var2); + void error(String var1, Object... var2); } @@ -34,14 +38,14 @@ public class Logger implements ILogger { private static LogLevel _logLevel = LogLevel.ERROR; private org.slf4j.Logger _logger = null; - private Logger(Class clazz){ + private Logger(Class clazz) { this._logger = LoggerFactory.getLogger(clazz); } static void initLogger(String logLevel) { - try{ + try { _logLevel = LogLevel.valueOf(logLevel); - }catch (IllegalArgumentException ex){ + } catch (IllegalArgumentException ex) { _logLevel = LogLevel.ERROR; } } @@ -52,35 +56,35 @@ public static Logger getLogger(Class clazz) { @Override public void trace(String var1, Object... var2) { - if(_logLevel == LogLevel.TRACE){ + if (_logLevel == LogLevel.TRACE) { _logger.error(var1, var2); } } @Override public void debug(String var1, Object... var2) { - if(_logLevel == LogLevel.DEBUG){ + if (_logLevel == LogLevel.DEBUG) { _logger.debug(var1, var2); } } @Override public void info(String var1, Object... var2) { - if(_logLevel == LogLevel.INFO){ + if (_logLevel == LogLevel.INFO) { _logger.error(var1, var2); } } @Override public void warn(String var1, Object... var2) { - if(_logLevel == LogLevel.WARN){ + if (_logLevel == LogLevel.WARN) { _logger.warn(var1, var2); } } @Override public void error(String var1, Object... var2) { - if(_logLevel == LogLevel.ERROR){ + if (_logLevel == LogLevel.ERROR) { _logger.error(var1, var2); } } diff --git a/src/main/java/com/securenative/ResourceStream.java b/src/main/java/com/securenative/ResourceStream.java index 81412f9..997f985 100644 --- a/src/main/java/com/securenative/ResourceStream.java +++ b/src/main/java/com/securenative/ResourceStream.java @@ -1,4 +1,5 @@ package com.securenative; + import java.io.InputStream; public interface ResourceStream { diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java index 5787550..20b0855 100644 --- a/src/main/java/com/securenative/SecureNative.java +++ b/src/main/java/com/securenative/SecureNative.java @@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; +import java.nio.file.Path; import java.util.stream.Collectors; import static com.securenative.utils.SignatureUtils.SIGNATURE_HEADER; @@ -32,7 +33,7 @@ private SecureNative(SecureNativeOptions options) throws SecureNativeSDKExceptio this.options = options; EventManager eventManager = new SecureNativeEventManager(new SecureNativeHTTPClient(options), options); - if(options.getAutoSend()){ + if (options.getAutoSend()) { eventManager.startEventsPersist(); } this.apiManager = new ApiManagerImpl(eventManager, options); @@ -51,16 +52,22 @@ public static SecureNative init(String apiKey) throws SecureNativeSDKException, if (Utils.isNullOrEmpty(apiKey)) { throw new SecureNativeConfigException("You must pass your SecureNative api key"); } - SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); + SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); SecureNativeOptions secureNativeOptions = builder.withApiKey(apiKey).build(); return init(secureNativeOptions); } + public static SecureNative init() throws SecureNativeSDKException, SecureNativeConfigException { SecureNativeOptions secureNativeOptions = ConfigurationManager.loadConfig(); return init(secureNativeOptions); } + public static SecureNative init(Path path) throws SecureNativeSDKException, SecureNativeConfigException { + SecureNativeOptions secureNativeOptions = ConfigurationManager.loadConfig(path); + return init(secureNativeOptions); + } + public static SecureNative getInstance() throws SecureNativeSDKIllegalStateException { if (secureNative == null) { throw new SecureNativeSDKIllegalStateException(); @@ -72,24 +79,24 @@ public SecureNativeOptions getOptions() { return options; } - public static SecureNativeConfigurationBuilder configBuilder(){ + public static SecureNativeConfigurationBuilder configBuilder() { return SecureNativeConfigurationBuilder.defaultConfigBuilder(); } - public static SecureNativeContextBuilder contextBuilder(){ + public static SecureNativeContextBuilder contextBuilder() { return SecureNativeContextBuilder.defaultContextBuilder(); } public boolean verifyRequestPayload(HttpServletRequest request) throws IOException { String requestSignature = request.getHeader(SIGNATURE_HEADER); - String body = request.getReader().lines().collect(Collectors.joining()); + String body = request.getReader().lines().collect(Collectors.joining()); return SignatureUtils.isValidSignature(requestSignature, body, this.options.getApiKey()); } @Override public void track(EventOptions eventOptions) { - this.apiManager.track(eventOptions); + this.apiManager.track(eventOptions); } @Override diff --git a/src/main/java/com/securenative/SecureNativeEventManager.java b/src/main/java/com/securenative/SecureNativeEventManager.java index edfa2a9..5cf3bc9 100644 --- a/src/main/java/com/securenative/SecureNativeEventManager.java +++ b/src/main/java/com/securenative/SecureNativeEventManager.java @@ -3,23 +3,25 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.securenative.config.SecureNativeOptions; import com.securenative.exceptions.SecureNativeHttpException; -import com.securenative.exceptions.SecureNativeInvalidUriException; import com.securenative.exceptions.SecureNativeParseException; import com.securenative.exceptions.SecureNativeSDKException; import com.securenative.http.HttpClient; import com.securenative.http.HttpResponse; import com.securenative.models.Event; import com.securenative.models.RequestOptions; -import com.securenative.config.SecureNativeOptions; import java.io.IOException; -import java.util.concurrent.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class SecureNativeEventManager implements EventManager { private static final Logger logger = Logger.getLogger(SecureNativeEventManager.class); - private final int[] coefficients = new int[] { 1, 1, 2, 3, 5, 8, 13 }; + private final int[] coefficients = new int[]{1, 1, 2, 3, 5, 8, 13}; private int attempt = 0; private Boolean sendEnabled = false; private ScheduledExecutorService scheduler; @@ -54,7 +56,7 @@ public T sendSync(Class clazz, Event event, String url) throws IOExceptio String responseBody = response.getBody(); try { return mapper.readValue(responseBody, clazz); - }catch (Exception ex){ + } catch (Exception ex) { logger.error("Failed to parse response body", ex.getMessage()); throw new SecureNativeParseException(ex.getMessage()); } @@ -77,10 +79,10 @@ public void sendAsync(Event event, String url, Boolean retry) { private void sendEvents() throws InterruptedException { if (!this.events.isEmpty() && this.sendEnabled) { - RequestOptions requestOptions = events.peek(); + RequestOptions requestOptions = events.peek(); try { String body = requestOptions.getBody(); - HttpResponse resp = this.httpClient.post(requestOptions.getUrl(), body); + HttpResponse resp = this.httpClient.post(requestOptions.getUrl(), body); if (resp.getStatusCode() == 401) { requestOptions.setRetry(false); } @@ -93,7 +95,7 @@ private void sendEvents() throws InterruptedException { } catch (Exception ex) { logger.error("Failed to send event", ex.getMessage()); if (requestOptions.getRetry()) { - if(attempt++ == coefficients.length){ + if (attempt++ == coefficients.length) { attempt = 0; } int backoff = coefficients[attempt] * this.options.getInterval(); @@ -101,7 +103,7 @@ private void sendEvents() throws InterruptedException { this.sendEnabled = false; Thread.sleep(backoff); this.sendEnabled = true; - }else{ + } else { // remove the event from queue, retry: false events.remove(requestOptions); } @@ -119,7 +121,10 @@ public void startEventsPersist() { this.sendEnabled = true; this.scheduler = Executors.newSingleThreadScheduledExecutor(); this.scheduler.scheduleWithFixedDelay(() -> { - try { sendEvents(); } catch (InterruptedException ignored) { } + try { + sendEvents(); + } catch (InterruptedException ignored) { + } }, 0, this.options.getInterval(), TimeUnit.MILLISECONDS); } @@ -131,7 +136,8 @@ public void stopEventsPersist() { this.scheduler.shutdown(); // drain event queue this.scheduler.awaitTermination(this.options.getTimeout(), TimeUnit.MILLISECONDS); - } catch (InterruptedException ignored) { } + } catch (InterruptedException ignored) { + } logger.debug("Stopped event persistence"); } diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index 01e5ad0..adc8c5f 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -4,17 +4,18 @@ import com.securenative.ResourceStreamImpl; import com.securenative.SecureNative; import com.securenative.enums.FailoverStrategy; -import com.securenative.exceptions.SecureNativeConfigException; import com.securenative.utils.Utils; import java.io.InputStream; import java.net.URL; +import java.nio.file.Path; import java.util.Properties; public class ConfigurationManager { private static final String DEFAULT_CONFIG_FILE = "securenative.properties"; private static final String CUSTOM_CONFIG_FILE_ENV_NAME = "SECURENATIVE_CONFIG_FILE"; private static ResourceStream resourceStream = new ResourceStreamImpl(); + private static String getEnvOrDefault(String envName, String defaultValue) { String envValue = System.getenv(envName); if (envValue != null) { @@ -51,23 +52,32 @@ private static Properties readResourceFile(String resourcePath) { return properties; } - private static String getPropertyOrEnvOrDefault(Properties properties, String key, Object defaultValue){ - String defaultStrValue = defaultValue == null? null: defaultValue.toString(); - Object res = properties.getOrDefault(key, getEnvOrDefault(key, defaultStrValue)); - return res == null? null: res.toString(); + private static String getPropertyOrEnvOrDefault(Properties properties, String key, Object defaultValue) { + String defaultStrValue = defaultValue == null ? null : defaultValue.toString(); + Object res = properties.getOrDefault(key, getEnvOrDefault(key, defaultStrValue)); + return res == null ? null : res.toString(); } - public static SecureNativeConfigurationBuilder configBuilder(){ - return SecureNativeConfigurationBuilder.defaultConfigBuilder(); + public static SecureNativeConfigurationBuilder configBuilder() { + return SecureNativeConfigurationBuilder.defaultConfigBuilder(); } - public static SecureNativeOptions loadConfig() throws SecureNativeConfigException { - SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); - SecureNativeOptions defaultOptions = builder.build(); + public static SecureNativeOptions loadConfig() { String resourceFilePath = getEnvOrDefault(CUSTOM_CONFIG_FILE_ENV_NAME, DEFAULT_CONFIG_FILE); Properties properties = readResourceFile(resourceFilePath); + return getOptions(properties); + } + + public static SecureNativeOptions loadConfig(Path path) { + Properties properties = readResourceFile(path.toString()); + return getOptions(properties); + } + + private static SecureNativeOptions getOptions(Properties properties) { + SecureNativeConfigurationBuilder builder = SecureNativeConfigurationBuilder.defaultConfigBuilder(); + SecureNativeOptions defaultOptions = builder.build(); - builder.withApiKey(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_KEY", defaultOptions.getApiKey())) + builder.withApiKey(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_KEY", defaultOptions.getApiKey())) .withApiUrl(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_API_URL", defaultOptions.getApiUrl())) .withInterval(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_INTERVAL", defaultOptions.getInterval()), defaultOptions.getInterval())) .withMaxEvents(Utils.parseIntegerOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_MAX_EVENTS", defaultOptions.getMaxEvents()), defaultOptions.getMaxEvents())) @@ -75,7 +85,7 @@ public static SecureNativeOptions loadConfig() throws SecureNativeConfigExceptio .withAutoSend(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_AUTO_SEND", defaultOptions.getAutoSend()), defaultOptions.getAutoSend())) .withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled())) .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())) - .withFailoverStrategy(FailoverStrategy.fromString(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy()),defaultOptions.getFailoverStrategy())); + .withFailoverStrategy(FailoverStrategy.fromString(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy()), defaultOptions.getFailoverStrategy())); return builder.build(); } diff --git a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java index a3b1f12..f52009c 100644 --- a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java +++ b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java @@ -48,7 +48,8 @@ public class SecureNativeConfigurationBuilder { */ private FailoverStrategy failoverStrategy; - private SecureNativeConfigurationBuilder(){ } + private SecureNativeConfigurationBuilder() { + } public static SecureNativeConfigurationBuilder defaultConfigBuilder() { return new SecureNativeConfigurationBuilder() diff --git a/src/main/java/com/securenative/context/SecureNativeContext.java b/src/main/java/com/securenative/context/SecureNativeContext.java index 153f918..436867d 100644 --- a/src/main/java/com/securenative/context/SecureNativeContext.java +++ b/src/main/java/com/securenative/context/SecureNativeContext.java @@ -7,11 +7,12 @@ public class SecureNativeContext { private String ip; private String remoteIp; private Map headers; - private String url; + private String url; private String method; private String body; - public SecureNativeContext() { } + public SecureNativeContext() { + } public SecureNativeContext(String clientToken, String ip, String remoteIp, Map headers, String url, String method, String body) { this.clientToken = clientToken; diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java index b329bc9..4dbdbbb 100644 --- a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -48,15 +48,15 @@ public SecureNativeContextBuilder withBody(String body) { return this; } - public static SecureNativeContextBuilder defaultContextBuilder(){ + public static SecureNativeContextBuilder defaultContextBuilder() { return new SecureNativeContextBuilder(); } public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) { - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request); String clientToken = RequestUtils.getCookieValueFromRequest(request, RequestUtils.SECURENATIVE_COOKIE); - if(Utils.isNullOrEmpty(clientToken)){ + if (Utils.isNullOrEmpty(clientToken)) { clientToken = RequestUtils.getSecureHeaderFromRequest(headers); } @@ -70,7 +70,7 @@ public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletReque .withBody(null); } - public SecureNativeContext build(){ + public SecureNativeContext build() { return this.context; } } diff --git a/src/main/java/com/securenative/enums/ApiRoute.java b/src/main/java/com/securenative/enums/ApiRoute.java index 2ed7239..1a262bc 100644 --- a/src/main/java/com/securenative/enums/ApiRoute.java +++ b/src/main/java/com/securenative/enums/ApiRoute.java @@ -1,16 +1,16 @@ package com.securenative.enums; public enum ApiRoute { - TRACK("track"), - VERIFY("verify"); + TRACK("track"), + VERIFY("verify"); - private String apiRoute; + private final String apiRoute; - public String getApiRoute() { - return apiRoute; - } + public String getApiRoute() { + return apiRoute; + } - ApiRoute(String apiRoute) { - this.apiRoute = apiRoute; - } + ApiRoute(String apiRoute) { + this.apiRoute = apiRoute; + } } \ No newline at end of file diff --git a/src/main/java/com/securenative/enums/FailoverStrategy.java b/src/main/java/com/securenative/enums/FailoverStrategy.java index d4ec4ea..a4f6070 100644 --- a/src/main/java/com/securenative/enums/FailoverStrategy.java +++ b/src/main/java/com/securenative/enums/FailoverStrategy.java @@ -1,13 +1,12 @@ package com.securenative.enums; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; public enum FailoverStrategy { FAIL_OPEN("fail-open"), FAIL_CLOSED("fail-closed"); - private String failoverStrategy; + private final String failoverStrategy; @JsonValue public String getFailoverStrategy() { @@ -17,7 +16,7 @@ public String getFailoverStrategy() { public static FailoverStrategy fromString(String key, FailoverStrategy failoverStrategy) { try { return FailoverStrategy.valueOf(key.replace("-", "_").toUpperCase()); - }catch (IllegalArgumentException ex){ + } catch (IllegalArgumentException ex) { return failoverStrategy; } } diff --git a/src/main/java/com/securenative/enums/RiskLevel.java b/src/main/java/com/securenative/enums/RiskLevel.java index 0850199..57ca1dd 100644 --- a/src/main/java/com/securenative/enums/RiskLevel.java +++ b/src/main/java/com/securenative/enums/RiskLevel.java @@ -8,7 +8,7 @@ public enum RiskLevel { MEDIUM("medium"), HIGH("high"); - private String riskLevel; + private final String riskLevel; @JsonValue public String getRiskLevel() { diff --git a/src/main/java/com/securenative/http/HttpClient.java b/src/main/java/com/securenative/http/HttpClient.java index 44bfaf8..04390ee 100644 --- a/src/main/java/com/securenative/http/HttpClient.java +++ b/src/main/java/com/securenative/http/HttpClient.java @@ -1,6 +1,5 @@ package com.securenative.http; - import java.io.IOException; public interface HttpClient { diff --git a/src/main/java/com/securenative/http/HttpResponse.java b/src/main/java/com/securenative/http/HttpResponse.java index c7aed51..ec1bc41 100644 --- a/src/main/java/com/securenative/http/HttpResponse.java +++ b/src/main/java/com/securenative/http/HttpResponse.java @@ -5,13 +5,15 @@ public class HttpResponse { private final int statusCode; private final String body; - public HttpResponse(Boolean ok, int statusCode, String body){ + public HttpResponse(Boolean ok, int statusCode, String body) { this.ok = ok; this.statusCode = statusCode; this.body = body; } - public Boolean isOk() { return ok; } + public Boolean isOk() { + return ok; + } public int getStatusCode() { return statusCode; diff --git a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java index b7a8516..9ea9204 100644 --- a/src/main/java/com/securenative/http/SecureNativeHTTPClient.java +++ b/src/main/java/com/securenative/http/SecureNativeHTTPClient.java @@ -23,13 +23,13 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { .Builder() .readTimeout(options.getTimeout(), TimeUnit.MILLISECONDS) .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT)) - .addInterceptor((chain) ->{ - Request request = chain.request(); - Request authenticatedRequest = request.newBuilder() - .header(USER_AGENT_HEADER, USER_AGENT_HEADER_VALUE) - .header(VERSION_HEADER, VersionUtils.getVersion()) - .header(AUTHORIZATION_HEADER, options.getApiKey()).build(); - return chain.proceed(authenticatedRequest); + .addInterceptor((chain) -> { + Request request = chain.request(); + Request authenticatedRequest = request.newBuilder() + .header(USER_AGENT_HEADER, USER_AGENT_HEADER_VALUE) + .header(VERSION_HEADER, VersionUtils.getVersion()) + .header(AUTHORIZATION_HEADER, options.getApiKey()).build(); + return chain.proceed(authenticatedRequest); }).build(); } @@ -37,7 +37,7 @@ public SecureNativeHTTPClient(SecureNativeOptions options) { @Override public HttpResponse post(String path, String payload) throws IOException { RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, payload); - + String url = String.format("%s/%s", this.options.getApiUrl(), path); Request request = new Request.Builder() @@ -45,9 +45,9 @@ public HttpResponse post(String path, String payload) throws IOException { .post(body) .build(); try (Response response = this.client.newCall(request).execute()) { - int statusCode = response.code(); - String responseBody = response.body().string(); - return new HttpResponse(response.isSuccessful(), statusCode, responseBody); + int statusCode = response.code(); + String responseBody = response.body().string(); + return new HttpResponse(response.isSuccessful(), statusCode, responseBody); } } } diff --git a/src/main/java/com/securenative/models/ClientToken.java b/src/main/java/com/securenative/models/ClientToken.java index 99dcc45..88918a1 100644 --- a/src/main/java/com/securenative/models/ClientToken.java +++ b/src/main/java/com/securenative/models/ClientToken.java @@ -1,6 +1,5 @@ package com.securenative.models; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; @@ -9,7 +8,8 @@ public class ClientToken { private String vid; private String fp; - public ClientToken() { } + public ClientToken() { + } @JsonCreator public ClientToken(@JsonProperty("cid") String cid, @JsonProperty("vid") String vid, @JsonProperty("fp") String fp) { diff --git a/src/main/java/com/securenative/models/Event.java b/src/main/java/com/securenative/models/Event.java index b280c04..d6ee3ae 100644 --- a/src/main/java/com/securenative/models/Event.java +++ b/src/main/java/com/securenative/models/Event.java @@ -1,6 +1,7 @@ package com.securenative.models; public interface Event { - String getEventType(); - String getTimestamp(); + String getEventType(); + + String getTimestamp(); } diff --git a/src/main/java/com/securenative/models/EventOptions.java b/src/main/java/com/securenative/models/EventOptions.java index 59a36f1..8f320ee 100644 --- a/src/main/java/com/securenative/models/EventOptions.java +++ b/src/main/java/com/securenative/models/EventOptions.java @@ -57,7 +57,11 @@ public void setProperties(Map properties) { this.properties = properties; } - public Date getTimestamp() { return timestamp; } + public Date getTimestamp() { + return timestamp; + } - public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } } diff --git a/src/main/java/com/securenative/models/RequestContext.java b/src/main/java/com/securenative/models/RequestContext.java index 286689c..ac57b05 100644 --- a/src/main/java/com/securenative/models/RequestContext.java +++ b/src/main/java/com/securenative/models/RequestContext.java @@ -12,7 +12,8 @@ public class RequestContext { private String url; private String method; - public RequestContext() { } + public RequestContext() { + } public RequestContext(String cid, String vid, String fp, String ip, String remoteIp, Map headers, String url, String method) { this.cid = cid; @@ -107,7 +108,7 @@ public RequestContextBuilder withMethod(String method) { return this; } - public RequestContext build(){ + public RequestContext build() { return new RequestContext(cid, vid, fp, ip, remoteIp, headers, url, method); } } diff --git a/src/main/java/com/securenative/models/SDKEvent.java b/src/main/java/com/securenative/models/SDKEvent.java index e47484c..ce17847 100644 --- a/src/main/java/com/securenative/models/SDKEvent.java +++ b/src/main/java/com/securenative/models/SDKEvent.java @@ -8,6 +8,7 @@ import com.securenative.context.SecureNativeContextBuilder; import com.securenative.utils.DateUtils; import com.securenative.utils.EncryptionUtils; + import java.util.*; public class SDKEvent implements Event { @@ -21,7 +22,7 @@ public class SDKEvent implements Event { public static final Logger logger = Logger.getLogger(SecureNative.class); public SDKEvent(EventOptions event, SecureNativeOptions options) { - SecureNativeContext context = event.getContext() != null? event.getContext() : SecureNativeContextBuilder.defaultContextBuilder().build(); + SecureNativeContext context = event.getContext() != null ? event.getContext() : SecureNativeContextBuilder.defaultContextBuilder().build(); ClientToken clientToken = decryptToken(context.getClientToken(), options.getApiKey()); @@ -29,16 +30,16 @@ public SDKEvent(EventOptions event, SecureNativeOptions options) { this.eventType = event.getEvent(); this.userId = event.getUserId(); this.userTraits = event.getUserTraits(); - this.request = new RequestContext.RequestContextBuilder() - .withCid(clientToken.getCid()) - .withVid(clientToken.getVid()) - .withFp(clientToken.getFp()) - .withIp(context.getIp()) - .withRemoteIp(context.getRemoteIp()) - .withMethod(context.getMethod()) - .withUrl(context.getUrl()) - .witHeaders(context.getHeaders()) - .build(); + this.request = new RequestContext.RequestContextBuilder() + .withCid(clientToken.getCid()) + .withVid(clientToken.getVid()) + .withFp(clientToken.getFp()) + .withIp(context.getIp()) + .withRemoteIp(context.getRemoteIp()) + .withMethod(context.getMethod()) + .withUrl(context.getUrl()) + .witHeaders(context.getHeaders()) + .build(); this.timestamp = DateUtils.toTimestamp(event.getTimestamp()); this.properties = event.getProperties(); } @@ -46,8 +47,8 @@ public SDKEvent(EventOptions event, SecureNativeOptions options) { private ClientToken decryptToken(String token, String key) { ObjectMapper mapper = new ObjectMapper(); try { - String decryptedClientToken = EncryptionUtils.decrypt(token, key); - return mapper.readValue(decryptedClientToken, ClientToken.class); + String decryptedClientToken = EncryptionUtils.decrypt(token, key); + return mapper.readValue(decryptedClientToken, ClientToken.class); } catch (Exception ex) { logger.error("Failed to decrypt token"); } diff --git a/src/main/java/com/securenative/utils/DateUtils.java b/src/main/java/com/securenative/utils/DateUtils.java index b33aa1e..12ac79f 100644 --- a/src/main/java/com/securenative/utils/DateUtils.java +++ b/src/main/java/com/securenative/utils/DateUtils.java @@ -7,6 +7,7 @@ public class DateUtils { private static final DateTimeFormatter ISO_8601_PATTERN = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + public static String generateTimestamp() { return ZonedDateTime.now(ZoneOffset.UTC).format(ISO_8601_PATTERN); } diff --git a/src/main/java/com/securenative/utils/EncryptionUtils.java b/src/main/java/com/securenative/utils/EncryptionUtils.java index fb1eaae..daa4f8d 100644 --- a/src/main/java/com/securenative/utils/EncryptionUtils.java +++ b/src/main/java/com/securenative/utils/EncryptionUtils.java @@ -1,7 +1,8 @@ package com.securenative.utils; import com.securenative.Logger; -import javax.crypto.*; + +import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; @@ -14,7 +15,7 @@ public class EncryptionUtils { private static final String EMPTY_STRING = ""; private static final Logger logger = Logger.getLogger(EncryptionUtils.class); private static final int AES_KEY_SIZE = 32; - private final static char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + private final static char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; private static byte[] hexToByteArray(String s) { byte[] retValue = null; @@ -35,13 +36,13 @@ private static String byteArrayToHex(byte[] byteArray) { return hexBuffer.toString(); } - private byte[] pad (byte[] buf, int size){ + private byte[] pad(byte[] buf, int size) { int bufLen = buf.length; - int padLen = size - bufLen%size; - byte[] padded = new byte[bufLen+padLen]; - padded = Arrays.copyOf(buf,bufLen+padLen); + int padLen = size - bufLen % size; + byte[] padded = new byte[bufLen + padLen]; + padded = Arrays.copyOf(buf, bufLen + padLen); for (int i = 0; i < padLen; i++) { - padded[bufLen+i] = (byte)padLen; + padded[bufLen + i] = (byte) padLen; } return padded; } @@ -66,7 +67,7 @@ public static String encrypt(String text, String key) { if (mod != 0) { text = String.format(text + "%" + (16 - mod) + "s", " "); } - return byteArrayToHex(cipher.doFinal(addAll(ivBytes,text.getBytes(StandardCharsets.UTF_8)))).trim(); + return byteArrayToHex(cipher.doFinal(addAll(ivBytes, text.getBytes(StandardCharsets.UTF_8)))).trim(); } catch (Exception ex) { logger.error("Unable to encrypt, err:", ex.getMessage()); } diff --git a/src/main/java/com/securenative/utils/IPUtils.java b/src/main/java/com/securenative/utils/IPUtils.java index 72fa47d..c02d07a 100644 --- a/src/main/java/com/securenative/utils/IPUtils.java +++ b/src/main/java/com/securenative/utils/IPUtils.java @@ -1,9 +1,7 @@ package com.securenative.utils; -import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +27,7 @@ public static boolean isValidPublicIp(String ip) { } return !(address.isSiteLocalAddress() || - address.isAnyLocalAddress() || + address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress() || address.isMulticastAddress()); diff --git a/src/main/java/com/securenative/utils/RequestUtils.java b/src/main/java/com/securenative/utils/RequestUtils.java index 7608e24..34795b6 100644 --- a/src/main/java/com/securenative/utils/RequestUtils.java +++ b/src/main/java/com/securenative/utils/RequestUtils.java @@ -7,7 +7,7 @@ public class RequestUtils { public final static String SECURENATIVE_COOKIE = "_sn"; public final static String SECURENATIVE_HEADER = "x-securenative"; - private final static List ipHeaders = Arrays.asList("x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"); + private final static List ipHeaders = Arrays.asList("x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"); public static Map getHeadersFromRequest(HttpServletRequest request) { Map headersMap = new HashMap<>(); @@ -37,31 +37,31 @@ public static String getCookieValueFromRequest(HttpServletRequest request, Strin public static String getClientIpFromRequest(HttpServletRequest request, Map headers) { Optional bestCandidate = Optional.empty(); - for (String ipHeader: ipHeaders) { - if(!headers.containsKey(ipHeader)){ + for (String ipHeader : ipHeaders) { + if (!headers.containsKey(ipHeader)) { continue; } String headerValue = headers.get(ipHeader); Optional candidateIp = Arrays.stream(headerValue.split(",")) - .map(String::trim) - .filter(IPUtils::isIpAddress) - .filter(IPUtils::isValidPublicIp) - .findFirst(); + .map(String::trim) + .filter(IPUtils::isIpAddress) + .filter(IPUtils::isValidPublicIp) + .findFirst(); - if(candidateIp.isPresent()){ - return candidateIp.get(); - }else if(!bestCandidate.isPresent()) { + if (candidateIp.isPresent()) { + return candidateIp.get(); + } else if (!bestCandidate.isPresent()) { bestCandidate = Arrays.stream(headerValue.split(",")) - .map(String::trim) - .filter(IPUtils::isLoopBack) - .findFirst(); + .map(String::trim) + .filter(IPUtils::isLoopBack) + .findFirst(); } } return bestCandidate.orElseGet(request::getRemoteAddr); } - public static String getRemoteIpFromRequest(HttpServletRequest request){ + public static String getRemoteIpFromRequest(HttpServletRequest request) { return request.getRemoteAddr(); } } diff --git a/src/main/java/com/securenative/utils/SignatureUtils.java b/src/main/java/com/securenative/utils/SignatureUtils.java index 2963eda..8f4b59a 100644 --- a/src/main/java/com/securenative/utils/SignatureUtils.java +++ b/src/main/java/com/securenative/utils/SignatureUtils.java @@ -2,10 +2,7 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; import java.util.Formatter; -import java.util.stream.Collectors; import static com.securenative.utils.Utils.timingSafeEqual; @@ -28,7 +25,8 @@ private static String buildHmacSignature(String message, String key) { hasher.init(new SecretKeySpec(key.getBytes(), HMAC_SHA512)); byte[] hash = hasher.doFinal(message.getBytes()); return toHexString(hash); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } return ""; } diff --git a/src/main/java/com/securenative/utils/Utils.java b/src/main/java/com/securenative/utils/Utils.java index c453a4f..b17fbb6 100644 --- a/src/main/java/com/securenative/utils/Utils.java +++ b/src/main/java/com/securenative/utils/Utils.java @@ -3,7 +3,6 @@ import com.securenative.Logger; - public class Utils { private static final Logger logger = Logger.getLogger(Utils.class); @@ -19,14 +18,14 @@ public static boolean timingSafeEqual(byte[] a, byte[] b) { return result == 0; } - public static Boolean isNullOrEmpty(String str){ + public static Boolean isNullOrEmpty(String str) { return str == null || str.length() == 0; } public static Integer parseIntegerOrDefault(String str, Integer defaultValue) { try { return Integer.valueOf(str); - }catch (NumberFormatException ex){ + } catch (NumberFormatException ex) { return defaultValue; } } @@ -34,7 +33,7 @@ public static Integer parseIntegerOrDefault(String str, Integer defaultValue) { public static Boolean parseBooleanOrDefault(String str, Boolean defaultValue) { try { return Boolean.valueOf(str); - }catch (Exception ex){ + } catch (Exception ex) { return defaultValue; } } diff --git a/src/main/java/com/securenative/utils/VersionUtils.java b/src/main/java/com/securenative/utils/VersionUtils.java index 3d75343..9eb4a7d 100644 --- a/src/main/java/com/securenative/utils/VersionUtils.java +++ b/src/main/java/com/securenative/utils/VersionUtils.java @@ -2,10 +2,6 @@ import com.securenative.ResourceStream; import com.securenative.ResourceStreamImpl; -import com.securenative.SecureNative; -import com.securenative.config.ConfigurationManager; -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import java.io.InputStream; import java.util.Properties; diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java index 65b9f4a..15dae59 100644 --- a/src/test/java/com/securenative/ApiManagerImplTest.java +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -10,7 +10,6 @@ import com.securenative.exceptions.SecureNativeSDKException; import com.securenative.http.HTTPServerMock; import com.securenative.models.EventOptions; -import com.securenative.models.UserTraits; import com.securenative.models.VerifyResult; import okhttp3.mockwebserver.RecordedRequest; import org.json.JSONException; @@ -38,11 +37,11 @@ public ApiManagerImplTest() throws SecureNativeInvalidOptionsException { .withIp("127.0.0.1") .withClientToken("SECURED_CLIENT_TOKEN") .withHeaders(Maps.defaultBuilder() - .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") - .build()) + .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") + .build()) .build(); - eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .userId("USER_ID") .userTraits("USER_NAME", "USER_EMAIL") .context(context) @@ -101,19 +100,21 @@ public void ShouldThrowWhenSendingMoreThan10CustomPropertiesToTrackEventTest() t eventManager.startEventsPersist(); ApiManager apiManager = new ApiManagerImpl(eventManager, options); - Map props = IntStream.range(0,11).boxed().collect(Collectors.toMap(i-> String.format("prop%d",i) , i-> String.format("val%d",i))); + Map props = IntStream.range(0, 11).boxed().collect(Collectors.toMap(i -> String.format("prop%d", i), i -> String.format("val%d", i))); try { - assertThrows(SecureNativeInvalidOptionsException.class, ()->{ + assertThrows(SecureNativeInvalidOptionsException.class, () -> { // track async event apiManager.track(EventOptionsBuilder.builder(EventTypes.LOG_IN) .properties(props) .build()); }); - }finally { - eventManager.stopEventsPersist(); + } finally { + eventManager.stopEventsPersist(); } - }; + } + + ; @Test @@ -168,7 +169,7 @@ public void ShouldNotRetryUnauthorizedTrackEventCallTest() throws SecureNativeSD assertThat(server.getRequestCount()).isEqualTo(1); } finally { - eventManager.stopEventsPersist(); + eventManager.stopEventsPersist(); } } @@ -190,7 +191,7 @@ public void ShouldCallVerifyEventTest() throws SecureNativeSDKException, JsonPro // call verify event - VerifyResult result = apiManager.verify(eventOptions); + VerifyResult result = apiManager.verify(eventOptions); assertThat(result.getRiskLevel()).isEqualTo(verifyResult.getRiskLevel()); assertThat(result.getScore()).isEqualTo(verifyResult.getScore()); @@ -219,7 +220,7 @@ public void ShouldFailVerifyEventCallWhenUnauthorizedTest() throws SecureNativeS ApiManager apiManager = new ApiManagerImpl(eventManager, options); // call verify event - VerifyResult verifyResult = apiManager.verify(eventOptions); + VerifyResult verifyResult = apiManager.verify(eventOptions); assertThat(verifyResult.getRiskLevel()).isEqualTo(RiskLevel.LOW); assertThat(verifyResult.getScore()).isEqualTo(0); assertThat(verifyResult.getTriggers().length).isEqualTo(0); diff --git a/src/test/java/com/securenative/EventManagerTest.java b/src/test/java/com/securenative/EventManagerTest.java index 3447e47..0b624f1 100644 --- a/src/test/java/com/securenative/EventManagerTest.java +++ b/src/test/java/com/securenative/EventManagerTest.java @@ -27,25 +27,25 @@ public class EventManagerTest extends HTTPServerMock { @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should successfully send async event with status code 200") public void SendAsyncEventWithStatusCode200Test() throws SecureNativeSDKException, InterruptedException, JSONException { - configBuilder = ConfigurationManager.configBuilder() - .withApiKey("YOUR_API_KEY") - .withAutoSend(true) - .withInterval(10); + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY") + .withAutoSend(true) + .withInterval(10); client = sandbox().mock(200); eventManager = new SecureNativeEventManager(client, options); eventManager.startEventsPersist(); - eventManager.sendAsync( event, "some-path/to-api",true); + eventManager.sendAsync(event, "some-path/to-api", true); - try{ - RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + try { + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); String body = lastRequest != null ? lastRequest.getBody().readUtf8() : null; String expected = "{\"eventType\":\"custom-event\"}"; JSONAssert.assertEquals(expected, body, false); assertThat(new JSONObject(body).has("timestamp")).isTrue(); - }finally { + } finally { eventManager.stopEventsPersist(); } } @@ -144,7 +144,7 @@ public void ShouldNotRetrySendingAsyncEventWhenStatusCode401Test() throws Secure // should be called only once assertThat(server.getRequestCount()).isEqualTo(1); } finally { - eventManager.stopEventsPersist(); + eventManager.stopEventsPersist(); } } @@ -195,7 +195,8 @@ public void ShouldSuccessfullySendSyncEventWithStatusCode200Test() throws Secure JsonNode data = null; try { data = eventManager.sendSync(JsonNode.class, event, "some-path/to-api"); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } JSONAssert.assertEquals(resBody, data.toString(), false); @@ -222,7 +223,8 @@ public void ShouldSendSyncEventAndHandleInvalidJsonResponseTest() throws SecureN String resp = null; try { resp = eventManager.sendSync(String.class, event, "some-path/to-api"); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); //invalid json response will turn into null @@ -241,7 +243,7 @@ public void ShouldSendSyncEventAndHandleInvalidRequestUrlTest() throws SecureNat eventManager = new SecureNativeEventManager(client, options); try { - Object obj = eventManager.sendSync(Object.class, event, "path what"); + Object obj = eventManager.sendSync(Object.class, event, "path what"); assertThat(obj).isNull(); } catch (Exception ignored) { @@ -261,9 +263,9 @@ public void ShouldSendSyncEventAndFailWhenStatusCode401Test() throws SecureNativ try { // track async event - eventManager.sendSync(Object.class, event, "some-path/to-api"); + eventManager.sendSync(Object.class, event, "some-path/to-api"); } catch (SecureNativeParseException | IOException ex) { - RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); assertThat(lastRequest).isNotNull(); assertThat(ex.getMessage()).contains("401"); } @@ -281,9 +283,9 @@ public void ShouldSendSyncEventAndFailWhenStatusCode500Test() throws SecureNativ try { // track async event - eventManager.sendSync(Object.class, event, "some-path/to-api"); + eventManager.sendSync(Object.class, event, "some-path/to-api"); } catch (Exception ex) { - RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); + RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); assertThat(lastRequest).isNotNull(); assertThat(ex.getMessage()).contains("500"); } diff --git a/src/test/java/com/securenative/SecureNativeTest.java b/src/test/java/com/securenative/SecureNativeTest.java index a13e45b..f32b009 100644 --- a/src/test/java/com/securenative/SecureNativeTest.java +++ b/src/test/java/com/securenative/SecureNativeTest.java @@ -1,6 +1,5 @@ package com.securenative; -import com.securenative.config.ConfigurationManager; import com.securenative.config.SecureNativeOptions; import com.securenative.enums.FailoverStrategy; import com.securenative.exceptions.SecureNativeConfigException; @@ -16,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class SecureNativeTest{ +public class SecureNativeTest { @AfterEach public void cleanUp() throws NoSuchFieldException, IllegalAccessException { Field instance = SecureNative.class.getDeclaredField("secureNative"); @@ -28,7 +27,7 @@ public void cleanUp() throws NoSuchFieldException, IllegalAccessException { @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) @Order(1) @DisplayName("Should init SDK with all public methods defined") - public void initSDKWithPublicMethodsDefinedTest() { + public void initSDKWithPublicMethodsDefinedTest() { assertThat(SecureNative.class).hasDeclaredMethods("track", "verify"); } @@ -46,7 +45,7 @@ public void getSDKInstanceWithoutInitThrowsTest() { @Order(3) @DisplayName("Should throw when try init sdk without api key") public void initSDKWithoutApiKeyShouldThrowTest() throws SecureNativeConfigException, SecureNativeSDKException { - assertThrows(SecureNativeSDKException.class, ()->{ + assertThrows(SecureNativeSDKException.class, () -> { SecureNative secureNative = SecureNative.init(); }); } @@ -56,7 +55,7 @@ public void initSDKWithoutApiKeyShouldThrowTest() throws SecureNativeConfigExcep @Order(4) @DisplayName("Should throw when try init sdk with empty api key") public void initSDKWithEmptyApiKeyShouldThrowTest() { - assertThrows(SecureNativeConfigException.class, ()->{ + assertThrows(SecureNativeConfigException.class, () -> { SecureNative.init(""); }); } @@ -87,10 +86,10 @@ public void initSDKWithApiKeyAndDefaultsTest() throws SecureNativeConfigExceptio @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) @Order(6) @DisplayName("Should throw exception when SDK initialized twice") - public void initSDKTwiceWillThrowTest(){ - assertThrows(SecureNativeSDKException.class, ()->{ - SecureNative.init(); - SecureNative.init(); + public void initSDKTwiceWillThrowTest() { + assertThrows(SecureNativeSDKException.class, () -> { + SecureNative.init(); + SecureNative.init(); }); } @@ -112,12 +111,12 @@ public void initSDKWithApiKeyAndGetInstanceShouldMatchTest() throws SecureNative @DisplayName("Should init SDK with builder correctly") public void initSDKWithBuilderTest() throws SecureNativeConfigException, SecureNativeSDKException { SecureNative secureNative = SecureNative.init(SecureNative.configBuilder() - .withApiKey("API_KEY") - .withMaxEvents(10) - .withLogLevel("error") - .build()); + .withApiKey("API_KEY") + .withMaxEvents(10) + .withLogLevel("error") + .build()); - SecureNativeOptions options = secureNative.getOptions(); + SecureNativeOptions options = secureNative.getOptions(); assertThat(options).extracting("apiKey", "maxEvents", "logLevel") .containsExactly("API_KEY", 10, "error"); @@ -129,7 +128,7 @@ public void initSDKWithBuilderTest() throws SecureNativeConfigException, SecureN @DisplayName("Should init SDK with property file correctly") public void initSDKAndLoadFromPropertiesFileTest() throws SecureNativeConfigException, SecureNativeSDKException { SecureNative secureNative = SecureNative.init(); - SecureNativeOptions options = secureNative.getOptions(); + SecureNativeOptions options = secureNative.getOptions(); assertThat(options).extracting("apiKey", "timeout") .containsExactly("SOME_API_KEY", 2000); } diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index a2f5a4f..6ae196f 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -16,7 +16,7 @@ @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ConfigurationManagerTest { - @SuppressWarnings({ "unchecked" }) + @SuppressWarnings({"unchecked"}) private static void setEnv(String name, String val) throws ReflectiveOperationException { Map env = System.getenv(); Field field = env.getClass().getDeclaredField("m"); @@ -30,17 +30,17 @@ private static void setEnv(String name, String val) throws ReflectiveOperationEx @DisplayName("Should parse config file correctly") public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { String config = String.join(System.getProperty("line.separator"), - "SECURENATIVE_API_KEY=SOME_API_KEY", - "SECURENATIVE_APP_NAME=SOME_APP_NAME", - "SECURENATIVE_API_URL=SOME_API_URL", - "SECURENATIVE_INTERVAL=1000", - "SECURENATIVE_HEARTBEAT_INTERVAL=5000", - "SECURENATIVE_MAX_EVENTS=100", - "SECURENATIVE_TIMEOUT=1500", - "SECURENATIVE_AUTO_SEND=true", - "SECURENATIVE_DISABLE=false", - "SECURENATIVE_LOG_LEVEL=fatal", - "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); + "SECURENATIVE_API_KEY=SOME_API_KEY", + "SECURENATIVE_APP_NAME=SOME_APP_NAME", + "SECURENATIVE_API_URL=SOME_API_URL", + "SECURENATIVE_INTERVAL=1000", + "SECURENATIVE_HEARTBEAT_INTERVAL=5000", + "SECURENATIVE_MAX_EVENTS=100", + "SECURENATIVE_TIMEOUT=1500", + "SECURENATIVE_AUTO_SEND=true", + "SECURENATIVE_DISABLE=false", + "SECURENATIVE_LOG_LEVEL=fatal", + "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); InputStream inputStream = new ByteArrayInputStream(config.getBytes()); @@ -54,7 +54,7 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { assertThat(options.getApiKey()).isEqualTo("SOME_API_KEY"); assertThat(options.getApiUrl()).isEqualTo("SOME_API_URL"); assertThat(options.getAutoSend()).isEqualTo(true); - assertThat(options.getDisabled()).isEqualTo( false); + assertThat(options.getDisabled()).isEqualTo(false); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); assertThat(options.getInterval()).isEqualTo(1000); assertThat(options.getLogLevel()).isEqualTo("fatal"); @@ -72,7 +72,7 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { public void IgnoreUnknownConfigInPropertiesFileTest() throws SecureNativeConfigException { String config = String.join(System.getProperty("line.separator"), "SECURENATIVE_UNKNOWN_KEY=SOME_UNKNOWN_KEY", - "SECURENATIVE_TIMEOUT=7500"); + "SECURENATIVE_TIMEOUT=7500"); InputStream inputStream = new ByteArrayInputStream(config.getBytes()); diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java index 04a480b..8bc37e5 100644 --- a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -16,7 +16,7 @@ public class SecureNativeContextBuilderTest { @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Create context from http servlet request test") - public void createContextFromHttpServletRequestTest(){ + public void createContextFromHttpServletRequestTest() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.setRequestURI("/login"); @@ -25,8 +25,8 @@ public void createContextFromHttpServletRequestTest(){ request.setRemoteAddr("51.68.201.122"); request.addHeader("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) - .build(); + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) + .build(); assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); assertThat(context.getIp()).isEqualTo("51.68.201.122"); @@ -40,7 +40,7 @@ public void createContextFromHttpServletRequestTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Create context from http servlet request with cookie test") - public void createContextFromHttpServletRequestWithCookieTest(){ + public void createContextFromHttpServletRequestWithCookieTest() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.setRequestURI("/login"); @@ -49,8 +49,8 @@ public void createContextFromHttpServletRequestWithCookieTest(){ request.setRemoteAddr("51.68.201.122"); request.setCookies(new Cookie("_sn", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a")); - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) - .build(); + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) + .build(); assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); assertThat(context.getIp()).isEqualTo("51.68.201.122"); @@ -65,8 +65,8 @@ public void createContextFromHttpServletRequestWithCookieTest(){ @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Create default context builder") public void createDefaultContextBuilderTest() { - SecureNativeContext context = SecureNativeContextBuilder.defaultContextBuilder() - .build(); + SecureNativeContext context = SecureNativeContextBuilder.defaultContextBuilder() + .build(); assertThat(context.getClientToken()).isNull(); assertThat(context.getIp()).isNull(); @@ -81,7 +81,7 @@ public void createDefaultContextBuilderTest() { @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Create custom context with ContextBuilder test") public void createCustomContextWithContextBuilderTest() { - SecureNativeContext context = SecureNativeContextBuilder + SecureNativeContext context = SecureNativeContextBuilder .defaultContextBuilder() .withUrl("/some-url") .withClientToken("SECRET_TOKEN") @@ -90,8 +90,8 @@ public void createCustomContextWithContextBuilderTest() { .withMethod("Get") .withRemoteIp("10.0.0.1") .withHeaders(Maps.defaultBuilder() - .put("header1", "value1") - .build()) + .put("header1", "value1") + .build()) .build(); assertThat(context.getUrl()).isEqualTo("/some-url"); assertThat(context.getClientToken()).isEqualTo("SECRET_TOKEN"); @@ -100,8 +100,8 @@ public void createCustomContextWithContextBuilderTest() { assertThat(context.getMethod()).isEqualTo("Get"); assertThat(context.getRemoteIp()).isEqualTo("10.0.0.1"); assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder() - .put("header1", "value1") - .build()); + .put("header1", "value1") + .build()); } } diff --git a/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java index 4a5e2cb..dff3aed 100644 --- a/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java +++ b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java @@ -1,4 +1,5 @@ package com.securenative.http; + import com.securenative.config.ConfigurationManager; import com.securenative.exceptions.SecureNativeInvalidUriException; import org.junit.jupiter.api.DisplayName; @@ -15,8 +16,8 @@ public class SecureNativeHTTPClientTest extends HTTPServerMock { @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should make simple http post call") public void shouldMakeSimplePostCallTest() throws IOException, SecureNativeInvalidUriException { - configBuilder = ConfigurationManager.configBuilder() - .withApiKey("YOUR_API_KEY"); + configBuilder = ConfigurationManager.configBuilder() + .withApiKey("YOUR_API_KEY"); client = sandbox().mock(200, "SOME_BODY"); diff --git a/src/test/java/com/securenative/utils/EncryptionUtilsTest.java b/src/test/java/com/securenative/utils/EncryptionUtilsTest.java index 9365994..60e26bd 100644 --- a/src/test/java/com/securenative/utils/EncryptionUtilsTest.java +++ b/src/test/java/com/securenative/utils/EncryptionUtilsTest.java @@ -23,8 +23,8 @@ public void encryptTest() { @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should decrypt message correctly") - public void decryptTest(){ - String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; + public void decryptTest() { + String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; String result = EncryptionUtils.decrypt(encryptedPayload, SECRET_KEY); Assertions.assertThat(result).isEqualTo(PAYLOAD); } @@ -32,7 +32,7 @@ public void decryptTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should encrypt and decrypt message correctly") - public void encryptDecryptTest(){ + public void encryptDecryptTest() { String encRes = EncryptionUtils.encrypt(PAYLOAD, SECRET_KEY); String decRes = EncryptionUtils.decrypt(encRes, SECRET_KEY); Assertions.assertThat(decRes).isEqualTo(PAYLOAD); @@ -41,7 +41,7 @@ public void encryptDecryptTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should handle encryption with short key") - public void encryptWithInvalidKeyLenTest(){ + public void encryptWithInvalidKeyLenTest() { String secretKey = "BAD_KEY"; String result = EncryptionUtils.encrypt(PAYLOAD, secretKey); Assertions.assertThat(result).hasSize(0); @@ -50,9 +50,9 @@ public void encryptWithInvalidKeyLenTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should handle decryption with short key") - public void decryptWithInvalidKeyLenTest(){ + public void decryptWithInvalidKeyLenTest() { String secretKey = "BAD_KEY"; - String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; + String encryptedPayload = "5208ae703cc2fa0851347f55d3b76d3fd6035ee081d71a401e8bc92ebdc25d42440f62310bda60628537744ac03f200d78da9e61f1019ce02087b7ce6c976e7b2d8ad6aa978c532cea8f3e744cc6a5cafedc4ae6cd1b08a4ef75d6e37aa3c0c76954d16d57750be2980c2c91ac7ef0bbd0722abd59bf6be22493ea9b9759c3ff4d17f17ab670b0b6fc320e6de982313f1c4e74c0897f9f5a32d58e3e53050ae8fdbebba9009d0d1250fe34dcde1ebb42acbc22834a02f53889076140f0eb8db1"; String result = EncryptionUtils.decrypt(encryptedPayload, secretKey); @@ -62,7 +62,7 @@ public void decryptWithInvalidKeyLenTest(){ @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should decrypt with key which is too long") - public void encryptDecryptWithKeyWhichTooLongTest(){ + public void encryptDecryptWithKeyWhichTooLongTest() { String secretKey = "B00C42DAD33EAC6F6572DA756EA4915349C0A4F6B00C42DAD33EAC6F6572DA756EA4915349C0A4F6"; String encRes = EncryptionUtils.encrypt(PAYLOAD, secretKey); diff --git a/src/test/java/com/securenative/utils/VersionTest.java b/src/test/java/com/securenative/utils/VersionTest.java index d5c83fc..1611bf7 100644 --- a/src/test/java/com/securenative/utils/VersionTest.java +++ b/src/test/java/com/securenative/utils/VersionTest.java @@ -1,7 +1,6 @@ package com.securenative.utils; import com.securenative.ResourceStreamImpl; -import com.securenative.config.ConfigurationManager; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -18,8 +17,8 @@ public void testVersionExtraction() throws IOException { String props = String.join(System.getProperty("line.separator"), "version=1.0.0", - "groupId=com.securenative.java", - "artifactId=securenative-java"); + "groupId=com.securenative.java", + "artifactId=securenative-java"); InputStream inputStream = new ByteArrayInputStream(props.getBytes()); ResourceStreamImpl resourceStream = Mockito.spy(new ResourceStreamImpl()); From 1a6befad8839666e7fa1fe5fa3720c7c030449ac Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 13:37:23 +0300 Subject: [PATCH 55/82] Update readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 0d6fa82..4128dc4 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,12 @@ To get your *API KEY*, login to your SecureNative account and go to project sett SecureNative can automatically load your config from *securenative.properties* file or from the file that is specified in your *SECURENATIVE_CONFIG_FILE* env variable: ```java +// Options 1: Use default config file path SecureNative secureNative = SecureNative.init(); + +// Options 2: Use specific config file path +Path path = Paths.get("/path/to/securenative.properties"); +SecureNative secureNative = SecureNative.init(path); ``` ### Option 2: Initialize via API Key From 3ec8675f5a91f305381b8a8395ba72134778983e Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 13:39:21 +0300 Subject: [PATCH 56/82] Version bump --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6cc71d7..457f77f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.6 + 0.4.7 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 54b9b82d09a925ff30bd47b0edb0502e5c9da9ef Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 29 Jul 2020 13:53:03 +0300 Subject: [PATCH 57/82] Update gitignore --- .gitignore | 2 ++ .vscode/settings.json | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 4bb19c4..7cd28f6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ hs_err_pid* /.project *.iml .idea +.vscode +.DS_Store diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 1133129..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "automatic" -} \ No newline at end of file From b865da659418db983f6a8dc601334c30de1882e1 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 30 Jul 2020 13:45:15 +0300 Subject: [PATCH 58/82] Fix creating context from request --- pom.xml | 6 +++--- src/main/java/com/securenative/EventOptionsBuilder.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 457f77f..a5d4f6d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.7 + 0.4.8 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} @@ -65,7 +65,7 @@ - + org.apache.maven.plugins @@ -80,7 +80,7 @@ - + org.apache.maven.plugins diff --git a/src/main/java/com/securenative/EventOptionsBuilder.java b/src/main/java/com/securenative/EventOptionsBuilder.java index 63e8b65..4c8271e 100644 --- a/src/main/java/com/securenative/EventOptionsBuilder.java +++ b/src/main/java/com/securenative/EventOptionsBuilder.java @@ -68,7 +68,7 @@ public EventOptionsBuilder timestamp(Date timestamp) { } public EventOptions build() throws SecureNativeInvalidOptionsException { - if (this.eventOptions.getProperties().size() > MAX_PROPERTIES_SIZE) { + if (this.eventOptions.getProperties() != null && this.eventOptions.getProperties().size() > MAX_PROPERTIES_SIZE) { throw new SecureNativeInvalidOptionsException(String.format("You can have only up to %d custom properties", MAX_PROPERTIES_SIZE)); } return this.eventOptions; From 848cf73eecd5d2b0989da09e2dc54b3ea7dd9742 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 30 Jul 2020 15:12:14 +0300 Subject: [PATCH 59/82] Fix date utils --- pom.xml | 2 +- src/main/java/com/securenative/utils/DateUtils.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a5d4f6d..4f84ab5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.8 + 0.4.9 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/utils/DateUtils.java b/src/main/java/com/securenative/utils/DateUtils.java index 12ac79f..842a8e6 100644 --- a/src/main/java/com/securenative/utils/DateUtils.java +++ b/src/main/java/com/securenative/utils/DateUtils.java @@ -13,6 +13,9 @@ public static String generateTimestamp() { } public static String toTimestamp(Date date) { + if (date == null) { + date = new Date(); + } return ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC).format(ISO_8601_PATTERN); } } From fe6d6f45ad3865b263993adcc27e319e0a105f6a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 30 Jul 2020 15:16:54 +0300 Subject: [PATCH 60/82] Version bump --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4f84ab5..43810f9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.4.9 + 0.5.0 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From ecab00bba60d309cadcfcb5f461f5700f6f0fa0a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Thu, 30 Jul 2020 16:11:39 +0300 Subject: [PATCH 61/82] Fix loading resources from path --- pom.xml | 2 +- .../securenative/config/ConfigurationManager.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 43810f9..0ce1611 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.0 + 0.5.1 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index adc8c5f..e496fcc 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -6,6 +6,9 @@ import com.securenative.enums.FailoverStrategy; import com.securenative.utils.Utils; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; @@ -69,7 +72,15 @@ public static SecureNativeOptions loadConfig() { } public static SecureNativeOptions loadConfig(Path path) { - Properties properties = readResourceFile(path.toString()); + Properties properties = new Properties(); + InputStream input; + try { + input = new FileInputStream(path.toString()); + properties.load(input); + } catch (IOException ignore) { + + } + return getOptions(properties); } From 676c0f46502a83600745781989d0f273fb65f0d1 Mon Sep 17 00:00:00 2001 From: alexivsn Date: Tue, 4 Aug 2020 12:23:46 +0300 Subject: [PATCH 62/82] Added fix empty client token --- src/main/java/com/securenative/Logger.java | 2 -- src/main/java/com/securenative/models/SDKEvent.java | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/securenative/Logger.java b/src/main/java/com/securenative/Logger.java index ed67157..bb45314 100644 --- a/src/main/java/com/securenative/Logger.java +++ b/src/main/java/com/securenative/Logger.java @@ -89,5 +89,3 @@ public void error(String var1, Object... var2) { } } } - - diff --git a/src/main/java/com/securenative/models/SDKEvent.java b/src/main/java/com/securenative/models/SDKEvent.java index ce17847..2936c83 100644 --- a/src/main/java/com/securenative/models/SDKEvent.java +++ b/src/main/java/com/securenative/models/SDKEvent.java @@ -45,6 +45,9 @@ public SDKEvent(EventOptions event, SecureNativeOptions options) { } private ClientToken decryptToken(String token, String key) { + if (token == null || token.length() == 0) { + return new ClientToken(); + } ObjectMapper mapper = new ObjectMapper(); try { String decryptedClientToken = EncryptionUtils.decrypt(token, key); @@ -52,7 +55,6 @@ private ClientToken decryptToken(String token, String key) { } catch (Exception ex) { logger.error("Failed to decrypt token"); } - return new ClientToken(); } From 00376d2ac15dd906929ea7242cd391583990a158 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 9 Aug 2020 09:00:45 +0300 Subject: [PATCH 63/82] Fix default log level --- pom.xml | 2 +- src/main/java/com/securenative/Logger.java | 4 +--- .../com/securenative/http/SecureNativeHTTPClientTest.java | 8 ++------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 0ce1611..0b6daf2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.1 + 0.5.2 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/Logger.java b/src/main/java/com/securenative/Logger.java index ed67157..65372b8 100644 --- a/src/main/java/com/securenative/Logger.java +++ b/src/main/java/com/securenative/Logger.java @@ -45,9 +45,7 @@ private Logger(Class clazz) { static void initLogger(String logLevel) { try { _logLevel = LogLevel.valueOf(logLevel); - } catch (IllegalArgumentException ex) { - _logLevel = LogLevel.ERROR; - } + } catch (IllegalArgumentException ignored) {} } public static Logger getLogger(Class clazz) { diff --git a/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java index dff3aed..a5662f5 100644 --- a/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java +++ b/src/test/java/com/securenative/http/SecureNativeHTTPClientTest.java @@ -1,7 +1,6 @@ package com.securenative.http; import com.securenative.config.ConfigurationManager; -import com.securenative.exceptions.SecureNativeInvalidUriException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -15,12 +14,9 @@ public class SecureNativeHTTPClientTest extends HTTPServerMock { @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @DisplayName("Should make simple http post call") - public void shouldMakeSimplePostCallTest() throws IOException, SecureNativeInvalidUriException { - configBuilder = ConfigurationManager.configBuilder() - .withApiKey("YOUR_API_KEY"); - + public void shouldMakeSimplePostCallTest() throws IOException { + configBuilder = ConfigurationManager.configBuilder().withApiKey("YOUR_API_KEY"); client = sandbox().mock(200, "SOME_BODY"); - String payload = "{\"event\":\"SOME_EVENT_NAME\"}"; HttpResponse response = client.post("track", payload); From 84428b9a12470cdfbdb558470edde374f9b53024 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 9 Aug 2020 14:07:33 +0300 Subject: [PATCH 64/82] Fix log level --- pom.xml | 2 +- src/main/java/com/securenative/Logger.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0b6daf2..dca144d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.2 + 0.5.3 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/Logger.java b/src/main/java/com/securenative/Logger.java index 65372b8..d81e798 100644 --- a/src/main/java/com/securenative/Logger.java +++ b/src/main/java/com/securenative/Logger.java @@ -44,7 +44,7 @@ private Logger(Class clazz) { static void initLogger(String logLevel) { try { - _logLevel = LogLevel.valueOf(logLevel); + _logLevel = LogLevel.valueOf(logLevel.toLowerCase()); } catch (IllegalArgumentException ignored) {} } From a60efe0d0f63393189de9b3cecfe0bab2b8c36cc Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 9 Aug 2020 14:37:31 +0300 Subject: [PATCH 65/82] Version bump --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dca144d..a2b1af7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.3 + 0.5.4 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From 98b634f448d06f670a7af0e0f38cc7412ddfd1ee Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Tue, 25 Aug 2020 12:54:13 +0300 Subject: [PATCH 66/82] SN-1938 Validate user id --- .../java/com/securenative/ApiManager.java | 5 ++-- .../java/com/securenative/ApiManagerImpl.java | 5 ++-- .../java/com/securenative/SecureNative.java | 5 ++-- .../com/securenative/models/SDKEvent.java | 11 ++++++- .../com/securenative/ApiManagerImplTest.java | 30 ++++++++++++++----- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/securenative/ApiManager.java b/src/main/java/com/securenative/ApiManager.java index 8255ed2..551f4f1 100644 --- a/src/main/java/com/securenative/ApiManager.java +++ b/src/main/java/com/securenative/ApiManager.java @@ -1,10 +1,11 @@ package com.securenative; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; import com.securenative.models.EventOptions; import com.securenative.models.VerifyResult; public interface ApiManager { - void track(EventOptions eventOptions); + void track(EventOptions eventOptions) throws SecureNativeInvalidOptionsException; - VerifyResult verify(EventOptions eventOptions); + VerifyResult verify(EventOptions eventOptions) throws SecureNativeInvalidOptionsException; } diff --git a/src/main/java/com/securenative/ApiManagerImpl.java b/src/main/java/com/securenative/ApiManagerImpl.java index 1cae4a2..f7d7231 100644 --- a/src/main/java/com/securenative/ApiManagerImpl.java +++ b/src/main/java/com/securenative/ApiManagerImpl.java @@ -4,6 +4,7 @@ import com.securenative.enums.ApiRoute; import com.securenative.enums.FailoverStrategy; import com.securenative.enums.RiskLevel; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; import com.securenative.exceptions.SecureNativeSDKException; import com.securenative.models.Event; import com.securenative.models.EventOptions; @@ -21,14 +22,14 @@ public ApiManagerImpl(EventManager eventManager, SecureNativeOptions options) th } @Override - public void track(EventOptions eventOptions) { + public void track(EventOptions eventOptions) throws SecureNativeInvalidOptionsException { logger.info("Track event call"); Event event = new SDKEvent(eventOptions, this.options); this.eventManager.sendAsync(event, ApiRoute.TRACK.getApiRoute(), true); } @Override - public VerifyResult verify(EventOptions eventOptions) { + public VerifyResult verify(EventOptions eventOptions) throws SecureNativeInvalidOptionsException { logger.info("Verify event call"); Event event = new SDKEvent(eventOptions, this.options); try { diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java index 20b0855..e2b8484 100644 --- a/src/main/java/com/securenative/SecureNative.java +++ b/src/main/java/com/securenative/SecureNative.java @@ -5,6 +5,7 @@ import com.securenative.config.SecureNativeOptions; import com.securenative.context.SecureNativeContextBuilder; import com.securenative.exceptions.SecureNativeConfigException; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; import com.securenative.exceptions.SecureNativeSDKException; import com.securenative.exceptions.SecureNativeSDKIllegalStateException; import com.securenative.http.SecureNativeHTTPClient; @@ -95,12 +96,12 @@ public boolean verifyRequestPayload(HttpServletRequest request) throws IOExcepti } @Override - public void track(EventOptions eventOptions) { + public void track(EventOptions eventOptions) throws SecureNativeInvalidOptionsException { this.apiManager.track(eventOptions); } @Override - public VerifyResult verify(EventOptions eventOptions) { + public VerifyResult verify(EventOptions eventOptions) throws SecureNativeInvalidOptionsException { return this.apiManager.verify(eventOptions); } } \ No newline at end of file diff --git a/src/main/java/com/securenative/models/SDKEvent.java b/src/main/java/com/securenative/models/SDKEvent.java index ce17847..5e7ac45 100644 --- a/src/main/java/com/securenative/models/SDKEvent.java +++ b/src/main/java/com/securenative/models/SDKEvent.java @@ -6,6 +6,7 @@ import com.securenative.config.SecureNativeOptions; import com.securenative.context.SecureNativeContext; import com.securenative.context.SecureNativeContextBuilder; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; import com.securenative.utils.DateUtils; import com.securenative.utils.EncryptionUtils; @@ -21,7 +22,15 @@ public class SDKEvent implements Event { public Map properties; public static final Logger logger = Logger.getLogger(SecureNative.class); - public SDKEvent(EventOptions event, SecureNativeOptions options) { + public SDKEvent(EventOptions event, SecureNativeOptions options) throws SecureNativeInvalidOptionsException { + if (event.getUserId() == null || event.getUserId().length() <= 0 || event.getUserId().equals("")) { + throw new SecureNativeInvalidOptionsException("Invalid event structure; User Id is missing"); + } + + if (event.getEvent() == null || event.getEvent().length() <= 0 || event.getEvent().equals("")) { + throw new SecureNativeInvalidOptionsException("Invalid event structure; Event Type is missing"); + } + SecureNativeContext context = event.getContext() != null ? event.getContext() : SecureNativeContextBuilder.defaultContextBuilder().build(); ClientToken clientToken = decryptToken(context.getClientToken(), options.getApiKey()); diff --git a/src/test/java/com/securenative/ApiManagerImplTest.java b/src/test/java/com/securenative/ApiManagerImplTest.java index 15dae59..e145bac 100644 --- a/src/test/java/com/securenative/ApiManagerImplTest.java +++ b/src/test/java/com/securenative/ApiManagerImplTest.java @@ -80,6 +80,7 @@ public void ShouldCallTrackEventTest() throws SecureNativeSDKException, Interrup JSONAssert.assertEquals(expected, body, false); assertThat(new JSONObject(body).has("rid")).isTrue(); assertThat(new JSONObject(body).has("timestamp")).isTrue(); + } catch (SecureNativeInvalidOptionsException ignored) { } finally { eventManager.stopEventsPersist(); } @@ -114,8 +115,6 @@ public void ShouldThrowWhenSendingMoreThan10CustomPropertiesToTrackEventTest() t } } - ; - @Test @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) @@ -131,7 +130,10 @@ public void ShouldNotCallTrackEventWhenAutomaticPersistenceDisabledTest() throws ApiManager apiManager = new ApiManagerImpl(eventManager, options); // track async event - apiManager.track(eventOptions); + try { + apiManager.track(eventOptions); + } catch (SecureNativeInvalidOptionsException ignored) { + } // ensure event to be sent RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); @@ -156,7 +158,10 @@ public void ShouldNotRetryUnauthorizedTrackEventCallTest() throws SecureNativeSD ApiManager apiManager = new ApiManagerImpl(eventManager, options); // track async event - apiManager.track(eventOptions); + try { + apiManager.track(eventOptions); + } catch (SecureNativeInvalidOptionsException ignored) { + } try { // ensure event to be sent @@ -191,8 +196,13 @@ public void ShouldCallVerifyEventTest() throws SecureNativeSDKException, JsonPro // call verify event - VerifyResult result = apiManager.verify(eventOptions); + VerifyResult result = null; + try { + result = apiManager.verify(eventOptions); + } catch (SecureNativeInvalidOptionsException ignored) { + } + assert result != null; assertThat(result.getRiskLevel()).isEqualTo(verifyResult.getRiskLevel()); assertThat(result.getScore()).isEqualTo(verifyResult.getScore()); assertThat(result.getTriggers().length).isEqualTo(verifyResult.getTriggers().length); @@ -220,7 +230,13 @@ public void ShouldFailVerifyEventCallWhenUnauthorizedTest() throws SecureNativeS ApiManager apiManager = new ApiManagerImpl(eventManager, options); // call verify event - VerifyResult verifyResult = apiManager.verify(eventOptions); + VerifyResult verifyResult = null; + try { + verifyResult = apiManager.verify(eventOptions); + } catch (SecureNativeInvalidOptionsException ignored) { + } + + assert verifyResult != null; assertThat(verifyResult.getRiskLevel()).isEqualTo(RiskLevel.LOW); assertThat(verifyResult.getScore()).isEqualTo(0); assertThat(verifyResult.getTriggers().length).isEqualTo(0); @@ -230,8 +246,6 @@ public void ShouldFailVerifyEventCallWhenUnauthorizedTest() throws SecureNativeS RecordedRequest lastRequest = server.takeRequest(10 * options.getInterval(), TimeUnit.MILLISECONDS); String lastRequestBody = lastRequest != null ? lastRequest.getBody().readUtf8() : null; - String expected = "{\"eventType\":\"sn.user.login\",\"userId\":\"USER_ID\",\"userTraits\":{\"name\":\"USER_NAME'\",\"email\":\"USER_EMAIL'\",\"createdAt\":null},\"request\":{\"cid\":null,\"vid\":null,\"fp\":null,\"ip\":\"127.0.0.1\",\"remoteIp\":null,\"headers\":{\"user-agent\":\"Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405\"},\"url\":null,\"method\":null},\"properties\":{\"prop2\":true,\"prop1\":\"CUSTOM_PARAM_VALUE\",\"prop3\":3}}"; assertThat(lastRequestBody).isNotNull(); - } } From f49bd1e30e13b369e74e4a8343f14c48552af940 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Tue, 25 Aug 2020 12:55:51 +0300 Subject: [PATCH 67/82] SN-1938 Validate user id --- README.md | 20 ++++++++++---------- pom.xml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4128dc4..f1dc944 100644 --- a/README.md +++ b/README.md @@ -57,21 +57,21 @@ SecureNative can automatically load your config from *securenative.properties* f ```java // Options 1: Use default config file path -SecureNative secureNative = SecureNative.init(); +SecureNative securenative = SecureNative.init(); // Options 2: Use specific config file path Path path = Paths.get("/path/to/securenative.properties"); -SecureNative secureNative = SecureNative.init(path); +SecureNative securenative = SecureNative.init(path); ``` ### Option 2: Initialize via API Key ```java -SecureNative secureNative = SecureNative.init("YOUR_API_KEY"); +SecureNative securenative = SecureNative.init("YOUR_API_KEY"); ``` ### Option 3: Initialize via ConfigurationBuilder ```java -SecureNative secureNative = SecureNative.init(SecureNative.configBuilder() +SecureNative securenative = SecureNative.init(SecureNative.configBuilder() .withApiKey("API_KEY") .withMaxEvents(10) .withLogLevel("error") @@ -81,7 +81,7 @@ SecureNative secureNative = SecureNative.init(SecureNative.configBuilder() ## Getting SecureNative instance Once initialized, sdk will create a singleton instance which you can get: ```java -SecureNative secureNative = SecureNative.getInstance(); +SecureNative securenative = SecureNative.getInstance(); ``` ## Tracking events @@ -90,7 +90,7 @@ Once the SDK has been initialized, tracking requests sent through the SDK instance. Make sure you build event with the EventBuilder: ```java -SecureNative secureNative = SecureNative.getInstance(); +SecureNative securenative = SecureNative.getInstance(); SecureNativeContext context = SecureNative.contextBuilder() .withIp("127.0.0.1") @@ -136,7 +136,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { .timestamp(new Date()) .build(); - secureNative.track(eventOptions); + securenative.track(eventOptions); } ``` @@ -163,7 +163,7 @@ public void verify(HttpServletRequest request, HttpServletResponse response) { .timestamp(new Date()) .build(); - VerifyResult verifyResult = secureNative.verify(eventOptions); + VerifyResult verifyResult = securenative.verify(eventOptions); verifyResult.getRiskLevel(); // Low, Medium, High verifyResult.score(); // Risk score: 0 -1 (0 - Very Low, 1 - Very High) verifyResult.getTriggers(); // ["TOR", "New IP", "New City"] @@ -177,9 +177,9 @@ Apply our filter to verify the request is from us, example in spring: ```java @RequestMapping("/webhook") public void webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { - SecureNative secureNative = SecureNative.getInstance(); + SecureNative securenative = SecureNative.getInstance(); // Checks if request is verified - Boolean isVerified = secureNative.verifyRequestPayload(request); + Boolean isVerified = securenative.verifyRequestPayload(request); } ``` diff --git a/pom.xml b/pom.xml index a2b1af7..7346ab6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.4 + 0.5.5 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} From b28022ac219a8f2f0e2020c043c2d05ebb9adaa9 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Tue, 25 Aug 2020 13:03:31 +0300 Subject: [PATCH 68/82] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1dc944..295adde 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) .timestamp(new Date()) .build(); -secureNative.track(eventOptions); +securenative.track(eventOptions); ``` You can also create request context from HttpServletRequest: From 128256d8472595706c3b4e94775979a0bd819b2d Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 30 Aug 2020 11:11:08 +0300 Subject: [PATCH 69/82] SN-1938 Validate user-id and event type --- src/test/java/com/securenative/models/SDKEventTest.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/test/java/com/securenative/models/SDKEventTest.java diff --git a/src/test/java/com/securenative/models/SDKEventTest.java b/src/test/java/com/securenative/models/SDKEventTest.java new file mode 100644 index 0000000..22414f6 --- /dev/null +++ b/src/test/java/com/securenative/models/SDKEventTest.java @@ -0,0 +1,4 @@ +package com.securenative.models; + +public class SDKEventTest { +} From 9e1d75556d01585265dbc3330ad37af6cb8cb688 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 30 Aug 2020 11:25:07 +0300 Subject: [PATCH 70/82] Add sdkevent test --- .../com/securenative/models/SDKEventTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/test/java/com/securenative/models/SDKEventTest.java b/src/test/java/com/securenative/models/SDKEventTest.java index 22414f6..c26213f 100644 --- a/src/test/java/com/securenative/models/SDKEventTest.java +++ b/src/test/java/com/securenative/models/SDKEventTest.java @@ -1,4 +1,47 @@ package com.securenative.models; +import com.securenative.config.SecureNativeConfigurationBuilder; +import com.securenative.config.SecureNativeOptions; +import com.securenative.enums.EventTypes; +import com.securenative.exceptions.SecureNativeInvalidOptionsException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +import static org.junit.jupiter.api.Assertions.assertThrows; + public class SDKEventTest { + @Test + @DisplayName("Should throw when creating sdk event invalid user-id") + public void createSDKEventInvalidUserIdThrowTest() { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + EventOptions event = new EventOptions(EventTypes.LOG_IN.getType()); + event.setUserId(""); + + assertThrows(SecureNativeInvalidOptionsException.class, () -> { + SDKEvent sdkEvent = new SDKEvent(event, options); + }); + } + + @Test + @DisplayName("Should throw when creating sdk event without user-id") + public void createSDKEventWithoutUserIdThrowTest() { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + EventOptions event = new EventOptions(EventTypes.LOG_IN.getType()); + + assertThrows(SecureNativeInvalidOptionsException.class, () -> { + SDKEvent sdkEvent = new SDKEvent(event, options); + }); + } + + @Test + @DisplayName("Should throw when creating sdk event without event type") + public void createSDKEventWithoutEventTypeThrowTest() { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + EventOptions event = new EventOptions(""); + + assertThrows(SecureNativeInvalidOptionsException.class, () -> { + SDKEvent sdkEvent = new SDKEvent(event, options); + }); + } } From 456287e86050608b9616b97b6e4aab86f7b0b817 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 14 Oct 2020 12:31:53 +0300 Subject: [PATCH 71/82] Update readme --- README.md | 197 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 295adde..5cc39d6 100644 --- a/README.md +++ b/README.md @@ -57,31 +57,52 @@ SecureNative can automatically load your config from *securenative.properties* f ```java // Options 1: Use default config file path -SecureNative securenative = SecureNative.init(); +try { + SecureNative securenative = SecureNative.init(); +} catch (SecureNativeSDKException | SecureNativeConfigException e) { + e.printStackTrace(); +} // Options 2: Use specific config file path Path path = Paths.get("/path/to/securenative.properties"); -SecureNative securenative = SecureNative.init(path); +try { + SecureNative.init(path); +} catch (SecureNativeSDKException | SecureNativeConfigException e) { + System.err.printf("Could not initialize SecureNative sdk; %s%n", e); +} ``` ### Option 2: Initialize via API Key ```java -SecureNative securenative = SecureNative.init("YOUR_API_KEY"); +try { + SecureNative securenative = SecureNative.init("YOUR_API_KEY"); +} catch (SecureNativeSDKException | SecureNativeConfigException e) { + e.printStackTrace(); +} ``` ### Option 3: Initialize via ConfigurationBuilder ```java -SecureNative securenative = SecureNative.init(SecureNative.configBuilder() - .withApiKey("API_KEY") - .withMaxEvents(10) - .withLogLevel("error") - .build()); +try { + securenative = SecureNative.init(SecureNative.configBuilder() + .withApiKey("API_KEY") + .withMaxEvents(10) + .withLogLevel("error") + .build()); +} catch (SecureNativeSDKException e) { + e.printStackTrace(); +} ``` ## Getting SecureNative instance Once initialized, sdk will create a singleton instance which you can get: ```java -SecureNative securenative = SecureNative.getInstance(); +SecureNative securenative = null; +try { + securenative = SecureNative.getInstance(); +} catch (SecureNativeSDKIllegalStateException e) { + System.err.printf("Could not get SecureNative instance; %s%n", e); +} ``` ## Tracking events @@ -90,29 +111,45 @@ Once the SDK has been initialized, tracking requests sent through the SDK instance. Make sure you build event with the EventBuilder: ```java -SecureNative securenative = SecureNative.getInstance(); - -SecureNativeContext context = SecureNative.contextBuilder() - .withIp("127.0.0.1") - .withClientToken("SECURED_CLIENT_TOKEN") - .withHeaders(Maps.defaultBuilder() - .put("user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405") +public void track() { + SecureNative securenative = null; + try { + securenative = SecureNative.getInstance(); + } catch (SecureNativeSDKIllegalStateException e) { + System.err.printf("Could not get SecureNative instance; %s%n", e); + } + + SecureNativeContext context = SecureNative.contextBuilder() + .withIp("37.86.255.94") + .withClientToken("SECURENATIVE_CLIENT_TOKEN") + .withHeaders(Maps.defaultBuilder() + .put("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36") .build()) - .build(); - -EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") - .context(context) - .properties(Maps.builder() - .put("prop1", "CUSTOM_PARAM_VALUE") - .put("prop2", true) - .put("prop3", 3) - .build()) - .timestamp(new Date()) - .build(); - -securenative.track(eventOptions); + .build(); + + EventOptions eventOptions = null; + try { + eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("11") + .userTraits("track02", "t@somemail.com", "+01234566789") + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } + + try { + securenative.track(eventOptions); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } +} ``` You can also create request context from HttpServletRequest: @@ -120,23 +157,37 @@ You can also create request context from HttpServletRequest: ```java @RequestMapping("/track") public void track(HttpServletRequest request, HttpServletResponse response) { - SecureNativeContext context = SecureNative.contextBuilder() - .fromHttpServletRequest(request) - .build(); - - EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") - .context(context) - .properties(Maps.builder() - .put("prop1", "CUSTOM_PARAM_VALUE") - .put("prop2", true) - .put("prop3", 3) - .build()) - .timestamp(new Date()) - .build(); - - securenative.track(eventOptions); + SecureNative securenative = null; + try { + securenative = SecureNative.getInstance(); + } catch (SecureNativeSDKIllegalStateException e) { + System.err.printf("Could not get SecureNative instance; %s%n", e); + } + + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build(); + + EventOptions eventOptions = null; + try { + eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } + + try { + securenative.track(eventOptions); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } } ``` @@ -147,25 +198,34 @@ public void track(HttpServletRequest request, HttpServletResponse response) { ```java @RequestMapping("/verify") public void verify(HttpServletRequest request, HttpServletResponse response) { - SecureNativeContext context = SecureNative.contextBuilder() - .fromHttpServletRequest(request) - .build(); - - EventOptions eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") - .context(context) - .properties(Maps.builder() - .put("prop1", "CUSTOM_PARAM_VALUE") - .put("prop2", true) - .put("prop3", 3) - .build()) - .timestamp(new Date()) - .build(); + SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build(); - VerifyResult verifyResult = securenative.verify(eventOptions); + EventOptions eventOptions = null; + try { + eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) + .userId("USER_ID") + .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") + .context(context) + .properties(Maps.builder() + .put("prop1", "CUSTOM_PARAM_VALUE") + .put("prop2", true) + .put("prop3", 3) + .build()) + .timestamp(new Date()) + .build(); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } + + VerifyResult verifyResult = null; + try { + verifyResult = securenative.verify(eventOptions); + } catch (SecureNativeInvalidOptionsException e) { + e.printStackTrace(); + } + verifyResult.getRiskLevel(); // Low, Medium, High - verifyResult.score(); // Risk score: 0 -1 (0 - Very Low, 1 - Very High) + verifyResult.getScore(); // Risk score: 0 -1 (0 - Very Low, 1 - Very High) verifyResult.getTriggers(); // ["TOR", "New IP", "New City"] } ``` @@ -177,7 +237,12 @@ Apply our filter to verify the request is from us, example in spring: ```java @RequestMapping("/webhook") public void webhookEndpoint(HttpServletRequest request, HttpServletResponse response) { - SecureNative securenative = SecureNative.getInstance(); + SecureNative securenative = null; + try { + securenative = SecureNative.getInstance(); + } catch (SecureNativeSDKIllegalStateException e) { + System.err.printf("Could not get SecureNative instance; %s%n", e); + } // Checks if request is verified Boolean isVerified = securenative.verifyRequestPayload(request); From 5abafc845b53174c26079a0dacf6eb147229f514 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 14 Oct 2020 13:04:02 +0300 Subject: [PATCH 72/82] Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5cc39d6..a5daca1 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Once the SDK has been initialized, tracking requests sent through the SDK instance. Make sure you build event with the EventBuilder: ```java +@RequestMapping("/track") public void track() { SecureNative securenative = null; try { From 81c713bdf47efc837381fd3c735a54dadfa0f497 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 14 Oct 2020 13:11:58 +0300 Subject: [PATCH 73/82] Update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a5daca1..fcbed18 100644 --- a/README.md +++ b/README.md @@ -170,8 +170,8 @@ public void track(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = null; try { eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") + .userId("1234") + .userTraits("Your Name", "name@gmail.com", "+1234567890") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") @@ -204,8 +204,8 @@ public void verify(HttpServletRequest request, HttpServletResponse response) { EventOptions eventOptions = null; try { eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("USER_ID") - .userTraits("USER_NAME", "USER_EMAIL", "+01234566789") + .userId("1234") + .userTraits("Your Name", "name@gmail.com", "+1234567890") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") From 43608beed58aa5df446fedf2c5eff0e6e1f81d2c Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Wed, 14 Oct 2020 13:15:49 +0300 Subject: [PATCH 74/82] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fcbed18..9570bac 100644 --- a/README.md +++ b/README.md @@ -131,8 +131,8 @@ public void track() { EventOptions eventOptions = null; try { eventOptions = EventOptionsBuilder.builder(EventTypes.LOG_IN) - .userId("11") - .userTraits("track02", "t@somemail.com", "+01234566789") + .userId("1234") + .userTraits("Your Name", "name@gmail.com", "+1234567890") .context(context) .properties(Maps.builder() .put("prop1", "CUSTOM_PARAM_VALUE") From 7bf92ab6f75887bed7f167a992366fdbf88580d5 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 1 Nov 2020 17:46:07 +0200 Subject: [PATCH 75/82] Add proxy headers support --- .../config/ConfigurationManager.java | 14 +++++++++++--- .../config/SecureNativeConfigurationBuilder.java | 16 ++++++++++++++-- .../securenative/config/SecureNativeOptions.java | 14 +++++++++++++- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index e496fcc..807e7a7 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -7,11 +7,13 @@ import com.securenative.utils.Utils; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Objects; import java.util.Properties; public class ConfigurationManager { @@ -61,6 +63,12 @@ private static String getPropertyOrEnvOrDefault(Properties properties, String ke return res == null ? null : res.toString(); } + private static ArrayList getPropertyListOrEnvOrDefault(Properties properties, String key, Object defaultValue) { + String defaultStrValue = defaultValue == null ? null : defaultValue.toString(); + Object res = properties.getOrDefault(key, getEnvOrDefault(key, defaultStrValue)); + return res == null ? null : new ArrayList<>(Arrays.asList(res.toString().split(","))); + } + public static SecureNativeConfigurationBuilder configBuilder() { return SecureNativeConfigurationBuilder.defaultConfigBuilder(); } @@ -96,8 +104,8 @@ private static SecureNativeOptions getOptions(Properties properties) { .withAutoSend(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_AUTO_SEND", defaultOptions.getAutoSend()), defaultOptions.getAutoSend())) .withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled())) .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())) - .withFailoverStrategy(FailoverStrategy.fromString(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy()), defaultOptions.getFailoverStrategy())); - + .withFailoverStrategy(FailoverStrategy.fromString(Objects.requireNonNull(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy())), defaultOptions.getFailoverStrategy())) + .withProxyHeaders(getPropertyListOrEnvOrDefault(properties, "SECURENATIVE_PROXY_HEADERS", defaultOptions.getProxyHeaders())); return builder.build(); } } diff --git a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java index f52009c..10e271e 100644 --- a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java +++ b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java @@ -2,6 +2,8 @@ import com.securenative.enums.FailoverStrategy; +import java.util.ArrayList; + public class SecureNativeConfigurationBuilder { /** * Api Secret associated with SecureNative account @@ -48,6 +50,11 @@ public class SecureNativeConfigurationBuilder { */ private FailoverStrategy failoverStrategy; + /** + * Proxy Headers + */ + private ArrayList proxyHeaders; + private SecureNativeConfigurationBuilder() { } @@ -61,7 +68,8 @@ public static SecureNativeConfigurationBuilder defaultConfigBuilder() { .withAutoSend(true) .withDisable(false) .withLogLevel("fatal") - .withFailoverStrategy(FailoverStrategy.FAIL_OPEN); + .withFailoverStrategy(FailoverStrategy.FAIL_OPEN) + .withProxyHeaders(new ArrayList<>()); } public SecureNativeConfigurationBuilder withApiKey(String apiKey) { @@ -109,8 +117,12 @@ public SecureNativeConfigurationBuilder withFailoverStrategy(FailoverStrategy fa return this; } + public SecureNativeConfigurationBuilder withProxyHeaders(ArrayList proxyHeaders) { + this.proxyHeaders = proxyHeaders; + return this; + } public SecureNativeOptions build() { - return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy); + return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy, proxyHeaders); } } diff --git a/src/main/java/com/securenative/config/SecureNativeOptions.java b/src/main/java/com/securenative/config/SecureNativeOptions.java index 6873fbd..2295da4 100644 --- a/src/main/java/com/securenative/config/SecureNativeOptions.java +++ b/src/main/java/com/securenative/config/SecureNativeOptions.java @@ -2,6 +2,8 @@ import com.securenative.enums.FailoverStrategy; +import java.util.ArrayList; + public class SecureNativeOptions { /** * Api Secret associated with SecureNative account @@ -48,7 +50,12 @@ public class SecureNativeOptions { */ private final FailoverStrategy failoverStrategy; - public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy) { + /** + * Proxy Headers + */ + private final ArrayList proxyHeaders; + + public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy, ArrayList proxyHeaders) { this.apiKey = apiKey; this.apiUrl = apiUrl; this.interval = interval; @@ -58,6 +65,7 @@ public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEv this.disable = disable; this.logLevel = logLevel; this.failoverStrategy = failoverStrategy; + this.proxyHeaders = proxyHeaders; } public String getApiKey() { @@ -95,4 +103,8 @@ public String getLogLevel() { public FailoverStrategy getFailoverStrategy() { return failoverStrategy; } + + public ArrayList getProxyHeaders() { + return proxyHeaders; + } } From 9c7fbb1ced20a891b3adebbc2296425da6449575 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 1 Nov 2020 18:01:01 +0200 Subject: [PATCH 76/82] Add proxy headers support --- .../java/com/securenative/SecureNative.java | 4 ++ .../context/SecureNativeContextBuilder.java | 5 +- .../com/securenative/utils/RequestUtils.java | 22 ++++++++- .../SecureNativeContextBuilderTest.java | 46 +++++++++++-------- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/securenative/SecureNative.java b/src/main/java/com/securenative/SecureNative.java index e2b8484..bda3944 100644 --- a/src/main/java/com/securenative/SecureNative.java +++ b/src/main/java/com/securenative/SecureNative.java @@ -88,6 +88,10 @@ public static SecureNativeContextBuilder contextBuilder() { return SecureNativeContextBuilder.defaultContextBuilder(); } + public SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) { + return SecureNativeContextBuilder.fromHttpServletRequest(request, this.options); + } + public boolean verifyRequestPayload(HttpServletRequest request) throws IOException { String requestSignature = request.getHeader(SIGNATURE_HEADER); String body = request.getReader().lines().collect(Collectors.joining()); diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java index 4dbdbbb..64495cf 100644 --- a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -1,5 +1,6 @@ package com.securenative.context; +import com.securenative.config.SecureNativeOptions; import com.securenative.utils.RequestUtils; import com.securenative.utils.Utils; @@ -52,7 +53,7 @@ public static SecureNativeContextBuilder defaultContextBuilder() { return new SecureNativeContextBuilder(); } - public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) { + public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request, SecureNativeOptions options) { Map headers = RequestUtils.getHeadersFromRequest(request); String clientToken = RequestUtils.getCookieValueFromRequest(request, RequestUtils.SECURENATIVE_COOKIE); @@ -65,7 +66,7 @@ public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletReque .withMethod(request.getMethod()) .withHeaders(headers) .withClientToken(clientToken) - .withIp(RequestUtils.getClientIpFromRequest(request, headers)) + .withIp(RequestUtils.getClientIpFromRequest(request, headers, options)) .withRemoteIp(RequestUtils.getRemoteIpFromRequest(request)) .withBody(null); } diff --git a/src/main/java/com/securenative/utils/RequestUtils.java b/src/main/java/com/securenative/utils/RequestUtils.java index 34795b6..fdc77fe 100644 --- a/src/main/java/com/securenative/utils/RequestUtils.java +++ b/src/main/java/com/securenative/utils/RequestUtils.java @@ -1,5 +1,7 @@ package com.securenative.utils; +import com.securenative.config.SecureNativeOptions; + import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import java.util.*; @@ -35,7 +37,25 @@ public static String getCookieValueFromRequest(HttpServletRequest request, Strin return null; } - public static String getClientIpFromRequest(HttpServletRequest request, Map headers) { + public static String getClientIpFromRequest(HttpServletRequest request, Map headers, SecureNativeOptions options) { + if (options.getProxyHeaders().size() > 0) { + for (String header : options.getProxyHeaders()) { + if (headers.containsKey(header)) { + String headerValue = headers.get(header); + + Optional ip = Arrays.stream(headerValue.split(",")) + .map(String::trim) + .filter(IPUtils::isIpAddress) + .filter(IPUtils::isValidPublicIp) + .findFirst(); + + if (ip.isPresent()) { + return ip.get(); + } + } + } + } + Optional bestCandidate = Optional.empty(); for (String ipHeader : ipHeaders) { if (!headers.containsKey(ipHeader)) { diff --git a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java index 8bc37e5..6b20635 100644 --- a/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java +++ b/src/test/java/com/securenative/context/SecureNativeContextBuilderTest.java @@ -1,6 +1,10 @@ package com.securenative.context; import com.securenative.Maps; +import com.securenative.SecureNative; +import com.securenative.config.SecureNativeConfigurationBuilder; +import com.securenative.config.SecureNativeOptions; +import com.securenative.exceptions.SecureNativeSDKException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -25,16 +29,19 @@ public void createContextFromHttpServletRequestTest() { request.setRemoteAddr("51.68.201.122"); request.addHeader("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) - .build(); + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + try { + SecureNative secureNative = SecureNative.init(options); + SecureNativeContext context = secureNative.fromHttpServletRequest(request).build(); - assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); - assertThat(context.getIp()).isEqualTo("51.68.201.122"); - assertThat(context.getMethod()).isEqualTo("Post"); - assertThat(context.getUrl()).isEqualTo("/login"); - assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); - assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); - assertThat(context.getBody()).isNull(); + assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); + assertThat(context.getIp()).isEqualTo("51.68.201.122"); + assertThat(context.getMethod()).isEqualTo("Post"); + assertThat(context.getUrl()).isEqualTo("/login"); + assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); + assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("x-securenative", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); + assertThat(context.getBody()).isNull(); + } catch (SecureNativeSDKException ignored) {} } @Test @@ -49,16 +56,19 @@ public void createContextFromHttpServletRequestWithCookieTest() { request.setRemoteAddr("51.68.201.122"); request.setCookies(new Cookie("_sn", "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a")); - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request) - .build(); + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + try { + SecureNative secureNative = SecureNative.init(options); + SecureNativeContext context = secureNative.fromHttpServletRequest(request).build(); - assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); - assertThat(context.getIp()).isEqualTo("51.68.201.122"); - assertThat(context.getMethod()).isEqualTo("Post"); - assertThat(context.getUrl()).isEqualTo("/login"); - assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); - assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("Cookie", "_sn=71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); - assertThat(context.getBody()).isNull(); + assertThat(context.getClientToken()).isEqualTo("71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"); + assertThat(context.getIp()).isEqualTo("51.68.201.122"); + assertThat(context.getMethod()).isEqualTo("Post"); + assertThat(context.getUrl()).isEqualTo("/login"); + assertThat(context.getRemoteIp()).isEqualTo("51.68.201.122"); + assertThat(context.getHeaders()).isEqualTo(Maps.defaultBuilder().put("Cookie", "_sn=71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a").build()); + assertThat(context.getBody()).isNull(); + } catch (SecureNativeSDKException ignored) {} } @Test From d79c9382faec1e030d23e485d754c8f0f46f5a9a Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 1 Nov 2020 18:24:45 +0200 Subject: [PATCH 77/82] Add request utils tests --- README.md | 11 ++- pom.xml | 2 +- .../securenative/utils/RequestUtilsTest.java | 67 +++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/securenative/utils/RequestUtilsTest.java diff --git a/README.md b/README.md index 9570bac..04ce764 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) { System.err.printf("Could not get SecureNative instance; %s%n", e); } - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build(); + SecureNativeContext context = securenative.fromHttpServletRequest(request).build(); EventOptions eventOptions = null; try { @@ -199,7 +199,14 @@ public void track(HttpServletRequest request, HttpServletResponse response) { ```java @RequestMapping("/verify") public void verify(HttpServletRequest request, HttpServletResponse response) { - SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build(); +SecureNative securenative = null; + try { + securenative = SecureNative.getInstance(); + } catch (SecureNativeSDKIllegalStateException e) { + System.err.printf("Could not get SecureNative instance; %s%n", e); + } + + SecureNativeContext context = securenative.fromHttpServletRequest(request).build(); EventOptions eventOptions = null; try { diff --git a/pom.xml b/pom.xml index 7346ab6..3cc56ae 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.5 + 0.5.6 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/test/java/com/securenative/utils/RequestUtilsTest.java b/src/test/java/com/securenative/utils/RequestUtilsTest.java new file mode 100644 index 0000000..c94b058 --- /dev/null +++ b/src/test/java/com/securenative/utils/RequestUtilsTest.java @@ -0,0 +1,67 @@ +package com.securenative.utils; + +import com.securenative.config.SecureNativeConfigurationBuilder; +import com.securenative.config.SecureNativeOptions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RequestUtilsTest { + + @Test + @DisplayName("Extract ip using proxy headers ipv4") + public void ExtractRequestWithProxyHeadersIPV4() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() + .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("CF-Connecting-IP", "203.0.113.1"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("203.0.113.1")); + } + + @Test + @DisplayName("Extract ip using proxy headers ipv6") + public void ExtractRequestWithProxyHeadersIPV6() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() + .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("CF-Connecting-IP", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("Extract ip using proxy headers with multiple ipv4") + public void ExtractRequestWithProxyHeadersMultipleIPV4() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() + .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("CF-Connecting-IP", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } +} From 192fee6023f051bd9dceb5017c3edad6578ce6b7 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Sun, 1 Nov 2020 18:38:17 +0200 Subject: [PATCH 78/82] Add request utils tests --- .../config/ConfigurationManagerTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 6ae196f..9012f6d 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -9,6 +9,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -40,7 +41,8 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { "SECURENATIVE_AUTO_SEND=true", "SECURENATIVE_DISABLE=false", "SECURENATIVE_LOG_LEVEL=fatal", - "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); + "SECURENATIVE_FAILOVER_STRATEGY=fail-closed", + "SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip"); InputStream inputStream = new ByteArrayInputStream(config.getBytes()); @@ -60,6 +62,7 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getMaxEvents()).isEqualTo(100); assertThat(options.getTimeout()).isEqualTo(1500); + assertThat(options.getProxyHeaders().size() == 0); // restore resource stream ConfigurationManager.setResourceStream(new ResourceStreamImpl()); @@ -159,6 +162,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { assertThat(options.getDisabled()).isEqualTo(false); assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); + assertThat(options.getProxyHeaders().size() == 0); ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } @@ -177,6 +181,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, setEnv("SECURENATIVE_DISABLE", "true"); setEnv("SECURENATIVE_LOG_LEVEL", "fatal"); setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-closed"); + setEnv("SECURENATIVE_PROXY_HEADERS", "CF-Connecting-IP,Some-Random-Ip"); SecureNativeOptions options = ConfigurationManager.loadConfig(); @@ -189,6 +194,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, assertThat(options.getDisabled()).isEqualTo(true); assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); + assertThat(options.getProxyHeaders().size() == 2); setEnv("SECURENATIVE_API_KEY", ""); setEnv("SECURENATIVE_API_URL", ""); @@ -199,6 +205,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException, setEnv("SECURENATIVE_DISABLE", ""); setEnv("SECURENATIVE_LOG_LEVEL", ""); setEnv("SECURENATIVE_FAILOVER_STRATEGY", ""); + setEnv("SECURENATIVE_PROXY_HEADERS", ""); } @Test @@ -215,7 +222,8 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE "SECURENATIVE_AUTO_SEND=false", "SECURENATIVE_DISABLE=false", "SECURENATIVE_LOG_LEVEL=fatal", - "SECURENATIVE_FAILOVER_STRATEGY=fail-closed"); + "SECURENATIVE_FAILOVER_STRATEGY=fail-closed", + "SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip"); setEnv("SECURENATIVE_API_KEY", "API_KEY_FROM_ENV"); setEnv("SECURENATIVE_API_URL", "API_URL_ENV"); @@ -226,6 +234,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE setEnv("SECURENATIVE_DISABLE", "true"); setEnv("SECURENATIVE_LOG_LEVEL", "error"); setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-open"); + setEnv("SECURENATIVE_PROXY_HEADERS", "CF-Connecting-IP,Some-Random-Ip"); InputStream inputStream = new ByteArrayInputStream(config.getBytes()); @@ -234,6 +243,9 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE ConfigurationManager.setResourceStream(resourceStream); SecureNativeOptions options = ConfigurationManager.loadConfig(); + ArrayList proxyHeaders = new ArrayList<>(); + proxyHeaders.add("CF-Connecting-IP"); + proxyHeaders.add("Some-Random-Ip"); assertThat(options).isNotNull(); assertThat(options.getApiKey()).isEqualTo("API_KEY_FROM_FILE"); @@ -245,6 +257,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE assertThat(options.getDisabled()).isEqualTo(false); assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED); + assertThat(options.getProxyHeaders()).isEqualTo(proxyHeaders); setEnv("SECURENATIVE_API_KEY", ""); setEnv("SECURENATIVE_API_URL", ""); @@ -255,6 +268,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE setEnv("SECURENATIVE_DISABLE", ""); setEnv("SECURENATIVE_LOG_LEVEL", ""); setEnv("SECURENATIVE_FAILOVER_STRATEGY", ""); + setEnv("SECURENATIVE_PROXY_HEADERS", ""); // restore resource stream ConfigurationManager.setResourceStream(new ResourceStreamImpl()); From 84f4a5929605a28484a239787d680b981f0d7ccd Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Mon, 16 Nov 2020 11:20:10 +0200 Subject: [PATCH 79/82] Add ip extraction tests --- .../securenative/utils/RequestUtilsTest.java | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) diff --git a/src/test/java/com/securenative/utils/RequestUtilsTest.java b/src/test/java/com/securenative/utils/RequestUtilsTest.java index c94b058..8fd8033 100644 --- a/src/test/java/com/securenative/utils/RequestUtilsTest.java +++ b/src/test/java/com/securenative/utils/RequestUtilsTest.java @@ -64,4 +64,295 @@ public void ExtractRequestWithProxyHeadersMultipleIPV4() assertThat(clientIp.equals("141.246.115.116")); } + + @Test + @DisplayName("extract ip using x-forwarded-for header ipv6") + public void ExtractIpUsingXForwardedForHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-forwarded-for", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using x-forwarded-for header multiple ipv4") + public void ExtractMultipleIpUsingXForwardedForHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-forwarded-for", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using x-client-ip header ipv6") + public void ExtractIpUsingXClientIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-client-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using x-client-ip header multiple ipv4") + public void ExtractMultipleIpUsingXClientIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-client-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using x-real-ip header ipv6") + public void ExtractIpUsingXRealIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-real-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using x-real-ip header multiple ipv4") + public void ExtractMultipleIpUsingXRealIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-real-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using x-forwarded header ipv6") + public void ExtractIpUsingXForwardedHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-forwarded", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using x-forwarded header multiple ipv4") + public void ExtractMultipleIpUsingXForwardedHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-forwarded", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using x-cluster-client-ip header ipv6") + public void ExtractIpUsingXClusterClientIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-cluster-client-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using x-cluster-client-ip header multiple ipv4") + public void ExtractMultipleIpUsingXClusterClientIpHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-cluster-client-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using forwarded-for header ipv6") + public void ExtractIpUsingForwardedForHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("forwarded-for", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using forwarded-for header multiple ipv4") + public void ExtractMultipleIpUsingForwardedForHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("forwarded-for", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using forwarded header ipv6") + public void ExtractIpUsingForwardedHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("forwarded", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using forwarded header multiple ipv4") + public void ExtractMultipleIpUsingForwardedHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("forwarded", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using via header ipv6") + public void ExtractIpUsingViaHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("via", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); + } + + @Test + @DisplayName("extract ip using via header multiple ipv4") + public void ExtractMultipleIpUsingViaHeader() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("via", "141.246.115.116, 203.0.113.1, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("141.246.115.116")); + } + + @Test + @DisplayName("extract ip using priority with x forwarded for") + public void ExtractIpUsingPriorityWithXForwardedFor() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-forwarded-for", "203.0.113.1"); + request.addHeader("x-real-ip", "198.51.100.101"); + request.addHeader("x-client-ip", "198.51.100.102"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("203.0.113.1")); + } + + @Test + @DisplayName("extract ip using priority without x forwarded for") + public void ExtractIpUsingPriorityWithoutXForwardedFor() + { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("x-real-ip", "198.51.100.101"); + request.addHeader("x-client-ip", "203.0.113.1, 141.246.115.116, 12.34.56.3"); + + Map headers = RequestUtils.getHeadersFromRequest(request); + String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); + + assertThat(clientIp.equals("203.0.113.1")); + } } From 4379e998b48667fcb43db4f4ba41123425fd2aab Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Mon, 30 Nov 2020 11:22:44 +0200 Subject: [PATCH 80/82] Support pii data remove from config --- pom.xml | 2 +- .../config/ConfigurationManager.java | 4 +- .../SecureNativeConfigurationBuilder.java | 26 +- .../config/SecureNativeOptions.java | 22 +- .../context/SecureNativeContextBuilder.java | 2 +- .../com/securenative/utils/RequestUtils.java | 38 ++- .../config/ConfigurationManagerTest.java | 8 +- .../securenative/utils/RequestUtilsTest.java | 224 +++++++++++++----- 8 files changed, 250 insertions(+), 76 deletions(-) diff --git a/pom.xml b/pom.xml index 3cc56ae..61a01ee 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.securenative.java securenative-java jar - 0.5.6 + 0.5.7 https://github.com/securenative/securenative-java ${project.groupId}:${project.artifactId}:${project.version} diff --git a/src/main/java/com/securenative/config/ConfigurationManager.java b/src/main/java/com/securenative/config/ConfigurationManager.java index 807e7a7..2bea82c 100644 --- a/src/main/java/com/securenative/config/ConfigurationManager.java +++ b/src/main/java/com/securenative/config/ConfigurationManager.java @@ -105,7 +105,9 @@ private static SecureNativeOptions getOptions(Properties properties) { .withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled())) .withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel())) .withFailoverStrategy(FailoverStrategy.fromString(Objects.requireNonNull(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy())), defaultOptions.getFailoverStrategy())) - .withProxyHeaders(getPropertyListOrEnvOrDefault(properties, "SECURENATIVE_PROXY_HEADERS", defaultOptions.getProxyHeaders())); + .withProxyHeaders(getPropertyListOrEnvOrDefault(properties, "SECURENATIVE_PROXY_HEADERS", defaultOptions.getProxyHeaders())) + .withPiiHeaders(getPropertyListOrEnvOrDefault(properties, "SECURENATIVE_PII_HEADERS", defaultOptions.getPiiHeaders())) + .withPiiRegexPattern(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_PII_REGEX_PATTERN", defaultOptions.getPiiRegexPattern())); return builder.build(); } } diff --git a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java index 10e271e..2b93d76 100644 --- a/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java +++ b/src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java @@ -55,6 +55,16 @@ public class SecureNativeConfigurationBuilder { */ private ArrayList proxyHeaders; + /** + * Pii Headers + */ + private ArrayList piiHeaders; + + /** + * Pii Regex Pattern + */ + private String piiRegexPattern; + private SecureNativeConfigurationBuilder() { } @@ -69,7 +79,9 @@ public static SecureNativeConfigurationBuilder defaultConfigBuilder() { .withDisable(false) .withLogLevel("fatal") .withFailoverStrategy(FailoverStrategy.FAIL_OPEN) - .withProxyHeaders(new ArrayList<>()); + .withProxyHeaders(new ArrayList<>()) + .withPiiHeaders(new ArrayList<>()) + .withPiiRegexPattern(null); } public SecureNativeConfigurationBuilder withApiKey(String apiKey) { @@ -122,7 +134,17 @@ public SecureNativeConfigurationBuilder withProxyHeaders(ArrayList proxy return this; } + public SecureNativeConfigurationBuilder withPiiHeaders(ArrayList piiHeaders) { + this.piiHeaders = piiHeaders; + return this; + } + + public SecureNativeConfigurationBuilder withPiiRegexPattern(String piiRegexPattern) { + this.piiRegexPattern = piiRegexPattern; + return this; + } + public SecureNativeOptions build() { - return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy, proxyHeaders); + return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy, proxyHeaders, piiHeaders, piiRegexPattern); } } diff --git a/src/main/java/com/securenative/config/SecureNativeOptions.java b/src/main/java/com/securenative/config/SecureNativeOptions.java index 2295da4..1967368 100644 --- a/src/main/java/com/securenative/config/SecureNativeOptions.java +++ b/src/main/java/com/securenative/config/SecureNativeOptions.java @@ -55,7 +55,17 @@ public class SecureNativeOptions { */ private final ArrayList proxyHeaders; - public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy, ArrayList proxyHeaders) { + /** + * Pii Headers + */ + private final ArrayList piiHeaders; + + /** + * Pii Regex Pattern + */ + private final String piiRegexPattern; + + public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy, ArrayList proxyHeaders, ArrayList piiHeaders, String piiRegexPattern) { this.apiKey = apiKey; this.apiUrl = apiUrl; this.interval = interval; @@ -66,6 +76,8 @@ public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEv this.logLevel = logLevel; this.failoverStrategy = failoverStrategy; this.proxyHeaders = proxyHeaders; + this.piiHeaders = piiHeaders; + this.piiRegexPattern = piiRegexPattern; } public String getApiKey() { @@ -107,4 +119,12 @@ public FailoverStrategy getFailoverStrategy() { public ArrayList getProxyHeaders() { return proxyHeaders; } + + public ArrayList getPiiHeaders() { + return piiHeaders; + } + + public String getPiiRegexPattern() { + return piiRegexPattern; + } } diff --git a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java index 64495cf..86e44bf 100644 --- a/src/main/java/com/securenative/context/SecureNativeContextBuilder.java +++ b/src/main/java/com/securenative/context/SecureNativeContextBuilder.java @@ -54,7 +54,7 @@ public static SecureNativeContextBuilder defaultContextBuilder() { } public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request, SecureNativeOptions options) { - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, options); String clientToken = RequestUtils.getCookieValueFromRequest(request, RequestUtils.SECURENATIVE_COOKIE); if (Utils.isNullOrEmpty(clientToken)) { diff --git a/src/main/java/com/securenative/utils/RequestUtils.java b/src/main/java/com/securenative/utils/RequestUtils.java index fdc77fe..52bd3a7 100644 --- a/src/main/java/com/securenative/utils/RequestUtils.java +++ b/src/main/java/com/securenative/utils/RequestUtils.java @@ -5,19 +5,45 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class RequestUtils { public final static String SECURENATIVE_COOKIE = "_sn"; public final static String SECURENATIVE_HEADER = "x-securenative"; private final static List ipHeaders = Arrays.asList("x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"); + private final static List piiHeaders = Arrays.asList("authorization", "access_token", "apikey", "password", "passwd", "secret", "api_key"); - public static Map getHeadersFromRequest(HttpServletRequest request) { + public static Map getHeadersFromRequest(HttpServletRequest request, SecureNativeOptions options) { Map headersMap = new HashMap<>(); - for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { - String headerName = headerNames.nextElement(); - String headerValue = request.getHeader(headerName); - headersMap.put(headerName, headerValue); + if (options != null && options.getPiiHeaders().size() > 0) { + for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { + String headerName = headerNames.nextElement(); + if (!options.getPiiHeaders().contains(headerName.toLowerCase()) && !options.getPiiHeaders().contains(headerName.toUpperCase())) { + String headerValue = request.getHeader(headerName); + headersMap.put(headerName, headerValue); + } + } + } else if (options != null && options.getPiiRegexPattern() != null) { + for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { + String headerName = headerNames.nextElement(); + Pattern pattern = Pattern.compile(options.getPiiRegexPattern(), Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(headerName); + if (!matcher.find()) { + String headerValue = request.getHeader(headerName); + headersMap.put(headerName, headerValue); + } + } + } else { + for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { + String headerName = headerNames.nextElement(); + if (!piiHeaders.contains(headerName.toLowerCase()) && !piiHeaders.contains(headerName.toUpperCase())) { + String headerValue = request.getHeader(headerName); + headersMap.put(headerName, headerValue); + } + } } + return headersMap; } @@ -38,7 +64,7 @@ public static String getCookieValueFromRequest(HttpServletRequest request, Strin } public static String getClientIpFromRequest(HttpServletRequest request, Map headers, SecureNativeOptions options) { - if (options.getProxyHeaders().size() > 0) { + if (options != null && options.getProxyHeaders().size() > 0) { for (String header : options.getProxyHeaders()) { if (headers.containsKey(header)) { String headerValue = headers.get(header); diff --git a/src/test/java/com/securenative/config/ConfigurationManagerTest.java b/src/test/java/com/securenative/config/ConfigurationManagerTest.java index 9012f6d..0997128 100644 --- a/src/test/java/com/securenative/config/ConfigurationManagerTest.java +++ b/src/test/java/com/securenative/config/ConfigurationManagerTest.java @@ -42,7 +42,9 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { "SECURENATIVE_DISABLE=false", "SECURENATIVE_LOG_LEVEL=fatal", "SECURENATIVE_FAILOVER_STRATEGY=fail-closed", - "SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip"); + "SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip", + "SECURENATIVE_PII_HEADERS=authentication,apiKey", + "SECURENATIVE_PII_REGEX_PATTERN=/http_auth_/i"); InputStream inputStream = new ByteArrayInputStream(config.getBytes()); @@ -63,6 +65,8 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException { assertThat(options.getMaxEvents()).isEqualTo(100); assertThat(options.getTimeout()).isEqualTo(1500); assertThat(options.getProxyHeaders().size() == 0); + assertThat(options.getPiiHeaders().size() == 0); + assertThat(options.getPiiRegexPattern()).isEqualTo("/http_auth_/i"); // restore resource stream ConfigurationManager.setResourceStream(new ResourceStreamImpl()); @@ -163,6 +167,8 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException { assertThat(options.getLogLevel()).isEqualTo("fatal"); assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN); assertThat(options.getProxyHeaders().size() == 0); + assertThat(options.getPiiHeaders().size() == 0); + assertThat(options.getPiiRegexPattern()).isEqualTo(null); ConfigurationManager.setResourceStream(new ResourceStreamImpl()); } diff --git a/src/test/java/com/securenative/utils/RequestUtilsTest.java b/src/test/java/com/securenative/utils/RequestUtilsTest.java index 8fd8033..f530104 100644 --- a/src/test/java/com/securenative/utils/RequestUtilsTest.java +++ b/src/test/java/com/securenative/utils/RequestUtilsTest.java @@ -16,8 +16,7 @@ public class RequestUtilsTest { @Test @DisplayName("Extract ip using proxy headers ipv4") - public void ExtractRequestWithProxyHeadersIPV4() - { + public void ExtractRequestWithProxyHeadersIPV4() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); @@ -25,7 +24,7 @@ public void ExtractRequestWithProxyHeadersIPV4() request.setServerName("www.securenative.com"); request.addHeader("CF-Connecting-IP", "203.0.113.1"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("203.0.113.1")); @@ -33,8 +32,7 @@ public void ExtractRequestWithProxyHeadersIPV4() @Test @DisplayName("Extract ip using proxy headers ipv6") - public void ExtractRequestWithProxyHeadersIPV6() - { + public void ExtractRequestWithProxyHeadersIPV6() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); @@ -42,7 +40,7 @@ public void ExtractRequestWithProxyHeadersIPV6() request.setServerName("www.securenative.com"); request.addHeader("CF-Connecting-IP", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -50,8 +48,7 @@ public void ExtractRequestWithProxyHeadersIPV6() @Test @DisplayName("Extract ip using proxy headers with multiple ipv4") - public void ExtractRequestWithProxyHeadersMultipleIPV4() - { + public void ExtractRequestWithProxyHeadersMultipleIPV4() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() .withProxyHeaders(new ArrayList<>(Collections.singleton("CF-Connecting-IP"))).build(); @@ -59,7 +56,7 @@ public void ExtractRequestWithProxyHeadersMultipleIPV4() request.setServerName("www.securenative.com"); request.addHeader("CF-Connecting-IP", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -67,15 +64,14 @@ public void ExtractRequestWithProxyHeadersMultipleIPV4() @Test @DisplayName("extract ip using x-forwarded-for header ipv6") - public void ExtractIpUsingXForwardedForHeader() - { + public void ExtractIpUsingXForwardedForHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-forwarded-for", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -83,15 +79,14 @@ public void ExtractIpUsingXForwardedForHeader() @Test @DisplayName("extract ip using x-forwarded-for header multiple ipv4") - public void ExtractMultipleIpUsingXForwardedForHeader() - { + public void ExtractMultipleIpUsingXForwardedForHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-forwarded-for", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -99,15 +94,14 @@ public void ExtractMultipleIpUsingXForwardedForHeader() @Test @DisplayName("extract ip using x-client-ip header ipv6") - public void ExtractIpUsingXClientIpHeader() - { + public void ExtractIpUsingXClientIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-client-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -115,15 +109,14 @@ public void ExtractIpUsingXClientIpHeader() @Test @DisplayName("extract ip using x-client-ip header multiple ipv4") - public void ExtractMultipleIpUsingXClientIpHeader() - { + public void ExtractMultipleIpUsingXClientIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-client-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -131,15 +124,14 @@ public void ExtractMultipleIpUsingXClientIpHeader() @Test @DisplayName("extract ip using x-real-ip header ipv6") - public void ExtractIpUsingXRealIpHeader() - { + public void ExtractIpUsingXRealIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-real-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -147,15 +139,14 @@ public void ExtractIpUsingXRealIpHeader() @Test @DisplayName("extract ip using x-real-ip header multiple ipv4") - public void ExtractMultipleIpUsingXRealIpHeader() - { + public void ExtractMultipleIpUsingXRealIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-real-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -163,15 +154,14 @@ public void ExtractMultipleIpUsingXRealIpHeader() @Test @DisplayName("extract ip using x-forwarded header ipv6") - public void ExtractIpUsingXForwardedHeader() - { + public void ExtractIpUsingXForwardedHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-forwarded", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -179,15 +169,14 @@ public void ExtractIpUsingXForwardedHeader() @Test @DisplayName("extract ip using x-forwarded header multiple ipv4") - public void ExtractMultipleIpUsingXForwardedHeader() - { + public void ExtractMultipleIpUsingXForwardedHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-forwarded", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -195,15 +184,14 @@ public void ExtractMultipleIpUsingXForwardedHeader() @Test @DisplayName("extract ip using x-cluster-client-ip header ipv6") - public void ExtractIpUsingXClusterClientIpHeader() - { + public void ExtractIpUsingXClusterClientIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-cluster-client-ip", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -211,15 +199,14 @@ public void ExtractIpUsingXClusterClientIpHeader() @Test @DisplayName("extract ip using x-cluster-client-ip header multiple ipv4") - public void ExtractMultipleIpUsingXClusterClientIpHeader() - { + public void ExtractMultipleIpUsingXClusterClientIpHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("x-cluster-client-ip", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -227,15 +214,14 @@ public void ExtractMultipleIpUsingXClusterClientIpHeader() @Test @DisplayName("extract ip using forwarded-for header ipv6") - public void ExtractIpUsingForwardedForHeader() - { + public void ExtractIpUsingForwardedForHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("forwarded-for", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -243,15 +229,14 @@ public void ExtractIpUsingForwardedForHeader() @Test @DisplayName("extract ip using forwarded-for header multiple ipv4") - public void ExtractMultipleIpUsingForwardedForHeader() - { + public void ExtractMultipleIpUsingForwardedForHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("forwarded-for", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -259,15 +244,14 @@ public void ExtractMultipleIpUsingForwardedForHeader() @Test @DisplayName("extract ip using forwarded header ipv6") - public void ExtractIpUsingForwardedHeader() - { + public void ExtractIpUsingForwardedHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("forwarded", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -275,15 +259,14 @@ public void ExtractIpUsingForwardedHeader() @Test @DisplayName("extract ip using forwarded header multiple ipv4") - public void ExtractMultipleIpUsingForwardedHeader() - { + public void ExtractMultipleIpUsingForwardedHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("forwarded", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -291,15 +274,14 @@ public void ExtractMultipleIpUsingForwardedHeader() @Test @DisplayName("extract ip using via header ipv6") - public void ExtractIpUsingViaHeader() - { + public void ExtractIpUsingViaHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("via", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d")); @@ -307,15 +289,14 @@ public void ExtractIpUsingViaHeader() @Test @DisplayName("extract ip using via header multiple ipv4") - public void ExtractMultipleIpUsingViaHeader() - { + public void ExtractMultipleIpUsingViaHeader() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName("www.securenative.com"); request.addHeader("via", "141.246.115.116, 203.0.113.1, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("141.246.115.116")); @@ -323,8 +304,7 @@ public void ExtractMultipleIpUsingViaHeader() @Test @DisplayName("extract ip using priority with x forwarded for") - public void ExtractIpUsingPriorityWithXForwardedFor() - { + public void ExtractIpUsingPriorityWithXForwardedFor() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -333,7 +313,7 @@ public void ExtractIpUsingPriorityWithXForwardedFor() request.addHeader("x-real-ip", "198.51.100.101"); request.addHeader("x-client-ip", "198.51.100.102"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("203.0.113.1")); @@ -341,8 +321,7 @@ public void ExtractIpUsingPriorityWithXForwardedFor() @Test @DisplayName("extract ip using priority without x forwarded for") - public void ExtractIpUsingPriorityWithoutXForwardedFor() - { + public void ExtractIpUsingPriorityWithoutXForwardedFor() { SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder().build(); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -350,9 +329,128 @@ public void ExtractIpUsingPriorityWithoutXForwardedFor() request.addHeader("x-real-ip", "198.51.100.101"); request.addHeader("x-client-ip", "203.0.113.1, 141.246.115.116, 12.34.56.3"); - Map headers = RequestUtils.getHeadersFromRequest(request); + Map headers = RequestUtils.getHeadersFromRequest(request, null); String clientIp = RequestUtils.getClientIpFromRequest(request, headers, options); assertThat(clientIp.equals("203.0.113.1")); } + + @Test + @DisplayName("extract pii data data from headers") + public void ExtractPiiDataFromHeaders() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("Host", "net.example.com"); + request.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)"); + request.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + request.addHeader("Accept-Encoding", "gzip,deflate"); + request.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); + request.addHeader("Keep-Alive", "300"); + request.addHeader("Connection", "keep-alive"); + request.addHeader("Cookie", "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120"); + request.addHeader("Pragma", "no-cache"); + request.addHeader("Cache-Control", "no-cache"); + request.addHeader("authorization", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("access_token", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("apikey", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("password", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("passwd", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("secret", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("api_key", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + + Map headers = RequestUtils.getHeadersFromRequest(request, null); + + assertThat(!headers.containsKey("authorization")); + assertThat(!headers.containsKey("access_token")); + assertThat(!headers.containsKey("apikey")); + assertThat(!headers.containsKey("password")); + assertThat(!headers.containsKey("passwd")); + assertThat(!headers.containsKey("secret")); + assertThat(!headers.containsKey("api_key")); + } + + @Test + @DisplayName("extract pii data data from custom headers") + public void ExtractPiiDataFromCustomHeaders() { + ArrayList h = new ArrayList(){ + { + add("authorization"); + add("access_token"); + add("apikey"); + add("password"); + add("passwd"); + add("secret"); + add("api_key"); + } + }; + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() + .withPiiHeaders(h).build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("Host", "net.example.com"); + request.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)"); + request.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + request.addHeader("Accept-Encoding", "gzip,deflate"); + request.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); + request.addHeader("Keep-Alive", "300"); + request.addHeader("Connection", "keep-alive"); + request.addHeader("Cookie", "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120"); + request.addHeader("Pragma", "no-cache"); + request.addHeader("Cache-Control", "no-cache"); + request.addHeader("authorization", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("access_token", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("apikey", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("password", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("passwd", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("secret", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("api_key", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + + Map headers = RequestUtils.getHeadersFromRequest(request, options); + + assertThat(!headers.containsKey("authorization")); + assertThat(!headers.containsKey("access_token")); + assertThat(!headers.containsKey("apikey")); + assertThat(!headers.containsKey("password")); + assertThat(!headers.containsKey("passwd")); + assertThat(!headers.containsKey("secret")); + assertThat(!headers.containsKey("api_key")); + } + + @Test + @DisplayName("extract pii data data from regex pattern") + public void ExtractPiiDataFromRegexPattern() { + SecureNativeOptions options = SecureNativeConfigurationBuilder.defaultConfigBuilder() + .withPiiRegexPattern("((?i)(http_auth_)(\\w+)?)").build(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServerName("www.securenative.com"); + request.addHeader("Host", "net.example.com"); + request.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)"); + request.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + request.addHeader("Accept-Encoding", "gzip,deflate"); + request.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); + request.addHeader("Keep-Alive", "300"); + request.addHeader("Connection", "keep-alive"); + request.addHeader("Cookie", "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120"); + request.addHeader("Pragma", "no-cache"); + request.addHeader("Cache-Control", "no-cache"); + request.addHeader("http_auth_authorization", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_access_token", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_apikey", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_password", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_passwd", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_secret", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + request.addHeader("http_auth_api_key", "ylSkZIjbdWybfs4fUQe9BqP0LH5Z"); + + Map headers = RequestUtils.getHeadersFromRequest(request, options); + + assertThat(!headers.containsKey("http_auth_authorization")); + assertThat(!headers.containsKey("http_auth_access_token")); + assertThat(!headers.containsKey("http_auth_apikey")); + assertThat(!headers.containsKey("http_auth_password")); + assertThat(!headers.containsKey("http_auth_passwd")); + assertThat(!headers.containsKey("http_auth_secret")); + assertThat(!headers.containsKey("http_auth_api_key")); + } } From 48056fd0dc47f4d173905a382a73a349a3f45d13 Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Mon, 30 Nov 2020 16:43:37 +0200 Subject: [PATCH 81/82] Update readme --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/README.md b/README.md index 04ce764..b003462 100644 --- a/README.md +++ b/README.md @@ -256,3 +256,55 @@ public void webhookEndpoint(HttpServletRequest request, HttpServletResponse resp Boolean isVerified = securenative.verifyRequestPayload(request); } ``` + +## Extract proxy headers from cloud providers + +You can specify custom header keys to allow extraction of client ip from different providers. +This example demonstrates the usage of proxy headers for ip extraction from Cloudflare. + +### Option 1: Using config file +```properties +SECURENATIVE_API_KEY="YOUR_API_KEY" +SECURENATIVE_PROXY_HEADERS=["CF-Connecting-IP"] +``` + +Initialize sdk as shown above. + +### Options 2: Using ConfigurationBuilder + +```java +try { + securenative = SecureNative.init(SecureNative.configBuilder() + .withApiKey("API_KEY") + .WithProxyHeaders(new ["CF-Connecting-IP"]) + .build()); +} catch (SecureNativeSDKException e) { + e.printStackTrace(); +} +``` + +## Remove PII Data From Headers + +By default, SecureNative SDK remove any known pii headers from the received request. +We also support using custom pii headers and regex matching via configuration, for example: + +### Option 1: Using config file +```properties +SECURENATIVE_API_KEY="YOUR_API_KEY" +SECURENATIVE_PII_HEADERS=["apiKey"] +``` + +Initialize sdk as shown above. + +### Options 2: Using ConfigurationBuilder + +```java +try { + securenative = SecureNative.init(SecureNative.configBuilder() + .withApiKey("API_KEY") + .WithPiiRegexPattern(@"((?i)(http_auth_)(\w+)?)") + .build()); +} catch (SecureNativeSDKException e) { + e.printStackTrace(); +} +``` \ No newline at end of file From 2d450007bc31bdfd7f2b3c9e8841f314359e166d Mon Sep 17 00:00:00 2001 From: Inbal Tako Date: Mon, 30 Nov 2020 16:49:06 +0200 Subject: [PATCH 82/82] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b003462..ff6e4ee 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ Initialize sdk as shown above. try { securenative = SecureNative.init(SecureNative.configBuilder() .withApiKey("API_KEY") - .WithPiiRegexPattern(@"((?i)(http_auth_)(\w+)?)") + .WithPiiRegexPattern("((?i)(http_auth_)(\\w+)?)") .build()); } catch (SecureNativeSDKException e) { e.printStackTrace();