diff --git a/apps/dashboard-app/src/main/js/test/admin/status/summary.json b/apps/dashboard-app/src/main/js/test/admin/status/summary.json index abb4e71f9..98fb623a8 100644 --- a/apps/dashboard-app/src/main/js/test/admin/status/summary.json +++ b/apps/dashboard-app/src/main/js/test/admin/status/summary.json @@ -1 +1 @@ -{"isHub":true,"shrineVersion":"1.20.1-SNAPSHOT","shrineBuildDate":"2015-12-09 17:38:13","ontologyVersion":"UNKNOWN","ontologyTerm":"\\\\i2b2_DEMO\\i2b2\\Demographics\\Gender\\Male\\","adapterOk":true,"keystoreOk":true,"hubOk":true,"qepOk":true} \ No newline at end of file +{"isHub":true,"shrineVersion":"1.21.1-SNAPSHOT","shrineBuildDate":"2015-12-09 17:38:13","ontologyVersion":"UNKNOWN","ontologyTerm":"\\\\i2b2_DEMO\\i2b2\\Demographics\\Gender\\Male\\","adapterOk":true,"keystoreOk":true,"hubOk":true,"qepOk":true} \ No newline at end of file diff --git a/apps/dashboard-app/src/test/resources/testhappy/all b/apps/dashboard-app/src/test/resources/testhappy/all index 2883573e3..f99f11757 100644 --- a/apps/dashboard-app/src/test/resources/testhappy/all +++ b/apps/dashboard-app/src/test/resources/testhappy/all @@ -1,231 +1,231 @@ -1.20.1-SNAPSHOT +1.21.1-SNAPSHOT UNKNOWN Unknown (not available) UNKNOWN_BRANCH 2015-12-09 17:38:13 /opt/shrine/shrine.keystore JKS shrine-qa1.catalyst CN=shrine-qa1.catalyst, OU=SHRINE, O=SHRINE Network, L=Boston, ST=MA, C=US 16146903290006569830 CN=shrine-qa1.catalyst, OU=SHRINE, O=SHRINE Network, L=Boston, ST=MA, C=US 16146903290006569830 shrine-qa2 https://shrine-qa2.catalyst:6443/shrine/rest/adapter/requests shrine-qa3 https://shrine-qa3.catalyst:6443/shrine/rest/adapter/requests http://localhost:9090/i2b2/services/QueryToolService/ http://localhost:9090/i2b2/services/OntologyService/ true shrine-qa2 https://shrine-qa2.catalyst:6443/shrine/rest/adapter/requests shrine-qa3 https://shrine-qa3.catalyst:6443/shrine/rest/adapter/requests true 3 3 0 0 shrine-qa2 https://shrine-qa2.catalyst:6443/shrine/rest/adapter/requests shrine-qa3 https://shrine-qa3.catalyst:6443/shrine/rest/adapter/requests NodeId(shrine-qa1) 495 milliseconds 470 467 demo Demo TestQuery \\i2b2_DEMO\i2b2\Demographics\Gender\Male\ 2016-02-09T14:08:03.552-05:00 533 467 4 PATIENT_COUNT_XML false Number of patients CATNUM 82 2016-02-09T14:08:03.599-05:00 2016-02-09T14:08:03.834-05:00 Number of patients for "TestQuery" FINISHED FINISHED 563 shrine 562 nn80 561 ij22 560 ij22 559 ij22 558 ij22 557 ij22 556 ij22 555 ij22 554 ij22 3688545598348393564 2016-02-09T14:08:03.000-05:00 TestQuery 8712321963203038195 2016-02-09T14:08:03.000-05:00 TestQuery 6005239175421767145 2016-02-09T14:08:00.000-05:00 TestQuery 9026499910600011220 2016-02-09T14:07:59.000-05:00 TestQuery 6434168520361125850 2016-02-09T14:06:30.000-05:00 TestQuery 895589878038151935 2016-02-09T14:06:30.000-05:00 TestQuery 1321035232773846651 2016-02-04T11:18:07.000-05:00 TestQuery 6074862923207751151 2016-02-04T11:18:06.000-05:00 TestQuery 8223427794947022691 2016-02-03T15:37:39.000-05:00 19 years old@15:37:37 3479926717610425856 2016-02-02T16:33:53.000-05:00 TestQuery \ No newline at end of file diff --git a/apps/dashboard-app/src/test/scala/net/shrine/dashboard/DashboardServiceTest.scala b/apps/dashboard-app/src/test/scala/net/shrine/dashboard/DashboardServiceTest.scala index c14c8dc52..0591a69e7 100644 --- a/apps/dashboard-app/src/test/scala/net/shrine/dashboard/DashboardServiceTest.scala +++ b/apps/dashboard-app/src/test/scala/net/shrine/dashboard/DashboardServiceTest.scala @@ -1,295 +1,296 @@ package net.shrine.dashboard import java.math.BigInteger import java.security.PrivateKey import java.util.Date import io.jsonwebtoken.impl.TextCodec import io.jsonwebtoken.{SignatureAlgorithm, Jwts} import net.shrine.authorization.steward.OutboundUser import net.shrine.crypto.{KeyStoreDescriptorParser, KeyStoreCertCollection} import net.shrine.dashboard.jwtauth.ShrineJwtAuthenticator import net.shrine.i2b2.protocol.pm.User import net.shrine.protocol.Credential import org.json4s.native.JsonMethods.parse import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner import org.scalatest.FlatSpec import spray.http.HttpHeaders.Authorization import spray.http.{OAuth2BearerToken, HttpHeaders, BasicHttpCredentials} import spray.testkit.ScalatestRouteTest import spray.http.StatusCodes.{OK,PermanentRedirect,Unauthorized,NotFound} import scala.language.postfixOps @RunWith(classOf[JUnitRunner]) class DashboardServiceTest extends FlatSpec with ScalatestRouteTest with DashboardService { def actorRefFactory = system import scala.concurrent.duration._ implicit val routeTestTimeout = RouteTestTimeout(10 seconds) val adminUserName = "keith" val adminFullName = adminUserName /** * to run these tests with I2B2 * add a user named keith, to be the admin * add a Boolean parameter for keith, Admin, true * add all this user to the i2b2 project */ val adminCredentials = BasicHttpCredentials(adminUserName,"shh!") val brokenCredentials = BasicHttpCredentials(adminUserName,"wrong password") val adminUser = User( fullName = adminUserName, username = adminFullName, domain = "domain", credential = new Credential("admin's password",false), params = Map(), rolesByProject = Map() ) val adminOutboundUser = OutboundUser.createFromUser(adminUser) "DashboardService" should "return an OK and a valid outbound user for a user/whoami request" in { Get(s"/user/whoami") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val userJson = new String(body.data.toByteArray) val outboundUser = parse(userJson).extract[OutboundUser] assertResult(adminOutboundUser)(outboundUser) } } "DashboardService" should "return an OK and a valid outbound user for a user/whoami request and an '' " in { Get(s"/user/whoami") ~> addCredentials(brokenCredentials) ~> route ~> check { assertResult(OK)(status) val response = new String(body.data.toByteArray) assertResult(""""AuthenticationFailed"""")(response) } } "DashboardService" should "redirect several urls to client/index.html" in { Get() ~> route ~> check { status === PermanentRedirect header("Location") === "client/index.html" } Get("/") ~> route ~> check { status === PermanentRedirect header("Location") === "client/index.html" } Get("/index.html") ~> route ~> check { status === PermanentRedirect header("Location") === "client/index.html" } Get("/client") ~> route ~> check { status === PermanentRedirect header("Location") === "client/index.html" } Get("/client/") ~> route ~> check { status === PermanentRedirect header("Location") === "client/index.html" } } "DashboardService" should "return an OK and the right version string for an admin/happy/all test" in { Get(s"/admin/happy/all") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val allString = new String(body.data.toByteArray) //println(allString) //todo test it to see if it's right } } "DashboardService" should "return an OK and mess with the right version string for an admin/messWithHappyVersion test" in { Get(s"/admin/messWithHappyVersion") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val versionString = new String(body.data.toByteArray) //todo test it to see if it's right } } "DashboardService" should "return an OK for admin/status/config" in { Get(s"/admin/status/config") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val configString = new String(body.data.toByteArray) //println(configString) } } "DashboardService" should "return an OK for admin/status/classpath" in { Get(s"/admin/status/classpath") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val classpathString = new String(body.data.toByteArray) } } "DashboardService" should "return an OK for admin/status/options" in { Get(s"/admin/status/options") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val options = new String(body.data.toByteArray) } } "DashboardService" should "return an OK for admin/status/summary" in { Get(s"/admin/status/summary") ~> addCredentials(adminCredentials) ~> route ~> check { assertResult(OK)(status) val summary = new String(body.data.toByteArray) println(summary) } } val dashboardCredentials = BasicHttpCredentials(adminUserName,"shh!") "DashboardService" should "return an OK and pong for fromDashboard/ping" in { Get(s"/fromDashboard/ping") ~> addCredentials(ShrineJwtAuthenticator.createOAuthCredentials(adminUser)) ~> route ~> check { assertResult(OK)(status) val string = new String(body.data.toByteArray) assertResult(""""pong"""")(string) } } "DashboardService" should "reject a fromDashboard/ping with an expired jwts header" in { val config = DashboardConfigSource.config val shrineCertCollection: KeyStoreCertCollection = KeyStoreCertCollection.fromFileRecoverWithClassPath(KeyStoreDescriptorParser(config.getConfig("shrine.keystore"))) val base64Cert = new String(TextCodec.BASE64URL.encode(shrineCertCollection.myCert.get.getEncoded)) val key: PrivateKey = shrineCertCollection.myKeyPair.privateKey val expiration: Date = new Date(System.currentTimeMillis() - 300 * 1000) //bad for 5 minutes val jwtsString = Jwts.builder(). setHeaderParam("kid", base64Cert). setSubject(java.net.InetAddress.getLocalHost.getHostName). setExpiration(expiration). signWith(SignatureAlgorithm.RS512, key). compact() Get(s"/fromDashboard/ping") ~> addCredentials(OAuth2BearerToken(jwtsString)) ~> sealRoute(route) ~> check { assertResult(Unauthorized)(status) } } "DashboardService" should "reject a fromDashboard/ping with no subject" in { val config = DashboardConfigSource.config val shrineCertCollection: KeyStoreCertCollection = KeyStoreCertCollection.fromClassPathResource(KeyStoreDescriptorParser(config.getConfig("shrine.keystore"))) val base64Cert = new String(TextCodec.BASE64URL.encode(shrineCertCollection.myCert.get.getEncoded)) val key: PrivateKey = shrineCertCollection.myKeyPair.privateKey val expiration: Date = new Date(System.currentTimeMillis() + 30 * 1000) val jwtsString = Jwts.builder(). setHeaderParam("kid", base64Cert). setExpiration(expiration). signWith(SignatureAlgorithm.RS512, key). compact() Get(s"/fromDashboard/ping") ~> addCredentials(OAuth2BearerToken(jwtsString)) ~> sealRoute(route) ~> check { assertResult(Unauthorized)(status) } } "DashboardService" should "reject a fromDashboard/ping with no Authorization header" in { Get(s"/fromDashboard/ping") ~> sealRoute(route) ~> check { assertResult(Unauthorized)(status) } } "DashboardService" should "reject a fromDashboard/ping with an Authorization header for the wrong authorization spec" in { Get(s"/fromDashboard/ping") ~> addCredentials(adminCredentials) ~> sealRoute(route) ~> check { assertResult(Unauthorized)(status) } } + /* "DashboardService" should "not find a bogus web service to talk to" in { Get(s"/toDashboard/bogus.harvard.edu/ping") ~> addCredentials(adminCredentials) ~> sealRoute(route) ~> check { val string = new String(body.data.toByteArray) assertResult(NotFound)(status) } } - +*/ } diff --git a/commons/crypto/src/main/scala/net/shrine/crypto/KeyStoreDescriptor.scala b/commons/crypto/src/main/scala/net/shrine/crypto/KeyStoreDescriptor.scala index 700c2c321..e466879b1 100644 --- a/commons/crypto/src/main/scala/net/shrine/crypto/KeyStoreDescriptor.scala +++ b/commons/crypto/src/main/scala/net/shrine/crypto/KeyStoreDescriptor.scala @@ -1,14 +1,17 @@ package net.shrine.crypto /** * @author clint * @since Nov 22, 2013 */ //todo consolidate with KeyStoreParser, maybe combine the whole works into KeyStoreCertCollection's collection final case class KeyStoreDescriptor( file: String, password: String, privateKeyAlias: Option[String], caCertAliases: Seq[String], - keyStoreType: KeyStoreType = KeyStoreType.Default) \ No newline at end of file + keyStoreType: KeyStoreType = KeyStoreType.Default){ + + override def toString = scala.runtime.ScalaRunTime._toString(this.copy(password = "REDACTED")) +} \ No newline at end of file