Skip to content

Commit c86bd33

Browse files
authored
Merge pull request #25 from delphi-hub/feature/authentication
Introduced JWT based authorization for registry communication
2 parents 8657863 + 01193ed commit c86bd33

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (C) 2018 The Delphi Team.
2+
// See the LICENCE file distributed with this work for additional
3+
// information regarding copyright ownership.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
package authorization
17+
18+
import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim}
19+
import utils.CommonHelper
20+
21+
object AuthProvider {
22+
23+
def generateJwt(validFor: Long = 1, useGenericName: Boolean = false): String = {
24+
val claim = JwtClaim()
25+
.issuedNow
26+
.expiresIn(validFor * 60)
27+
.startsNow
28+
. + ("user_id", if (useGenericName) CommonHelper.configuration.instanceName else s"${CommonHelper.configuration.assignedID.get}")
29+
. + ("user_type", "Component")
30+
31+
32+
Jwt.encode(claim, CommonHelper.configuration.jwtSecretKey, JwtAlgorithm.HS256)
33+
}
34+
35+
}

app/utils/Configuration.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class Configuration(val bindPort: Int = ConfigFactory.load().getInt("app.portWeb
6565
case None => defaultWebApiPort
6666
}
6767

68+
val jwtSecretKey: String = sys.env.getOrElse("DELPHI_JWT_SECRET","changeme")
69+
6870
lazy val fallbackWebApiHost : String = sys.env.get("DELPHI_WEBAPI_URI") match {
6971
case Some(hostString) =>
7072
if(hostString.count(c => c == ':') == 2){

app/utils/instancemanagement/InstanceRegistry.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ import java.net.InetAddress
2020
import akka.actor.ActorSystem
2121
import akka.http.scaladsl.Http
2222
import akka.http.scaladsl.model._
23+
import akka.http.scaladsl.model.headers.RawHeader
2324
import akka.http.scaladsl.unmarshalling.Unmarshal
2425
import akka.stream.ActorMaterializer
2526
import akka.util.ByteString
27+
import authorization.AuthProvider
2628
import utils.instancemanagement.InstanceEnums.{ComponentType, InstanceState}
2729
import utils.{AppLogging, CommonHelper, Configuration}
2830

@@ -93,7 +95,10 @@ object InstanceRegistry extends InstanceJsonSupport with AppLogging
9395
method = HttpMethods.POST,
9496
configuration.instanceRegistryUri + ReportOperationType.toOperationUriString(operationType, id))
9597

96-
Await.result(Http(system).singleRequest(request) map {response =>
98+
val useGenericNameForToken = operationType == ReportOperationType.Start //Must use generic name for startup, no id known at that point
99+
100+
Await.result(Http(system).singleRequest(request.withHeaders(RawHeader("Authorization",
101+
s"Bearer ${AuthProvider.generateJwt(useGenericName = useGenericNameForToken)}"))) map { response =>
97102
if(response.status == StatusCodes.OK){
98103
log.info(s"Successfully reported ${operationType.toString} to Instance Registry.")
99104
Success()
@@ -146,7 +151,7 @@ object InstanceRegistry extends InstanceJsonSupport with AppLogging
146151
val request = HttpRequest(method = HttpMethods.GET, configuration.instanceRegistryUri +
147152
s"/matchingInstance?Id=${configuration.assignedID.getOrElse(-1)}&ComponentType=WebApi")
148153

149-
Await.result(Http(system).singleRequest(request) map {response =>
154+
Await.result(Http(system).singleRequest(request.withHeaders(RawHeader("Authorization",s"Bearer ${AuthProvider.generateJwt()}"))) map {response =>
150155
response.status match {
151156
case StatusCodes.OK =>
152157
val instanceString : String = Await.result(response.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String), 5 seconds)
@@ -187,7 +192,7 @@ object InstanceRegistry extends InstanceJsonSupport with AppLogging
187192
configuration.instanceRegistryUri +
188193
s"/matchingResult?CallerId=${configuration.assignedID.getOrElse(-1)}&MatchedInstanceId=$idToPost&MatchingSuccessful=$isWebApiReachable")
189194

190-
Await.result(Http(system).singleRequest(request) map {response =>
195+
Await.result(Http(system).singleRequest(request.withHeaders(RawHeader("Authorization",s"Bearer ${AuthProvider.generateJwt()}"))) map {response =>
191196
if(response.status == StatusCodes.OK){
192197
log.info("Successfully posted matching result to Instance Registry.")
193198
Success()
@@ -235,7 +240,7 @@ object InstanceRegistry extends InstanceJsonSupport with AppLogging
235240

236241
val request = HttpRequest(method = HttpMethods.POST, configuration.instanceRegistryUri + s"/deregister?Id=$id")
237242

238-
Await.result(Http(system).singleRequest(request) map {response =>
243+
Await.result(Http(system).singleRequest(request.withHeaders(RawHeader("Authorization",s"Bearer ${AuthProvider.generateJwt()}"))) map {response =>
239244
if(response.status == StatusCodes.OK){
240245
log.info("Successfully deregistered from Instance Registry.")
241246
Success()
@@ -255,7 +260,8 @@ object InstanceRegistry extends InstanceJsonSupport with AppLogging
255260

256261
def postInstance(instance : Instance, uri: String) () : Future[HttpResponse] = {
257262
val request = HttpRequest(method = HttpMethods.POST, uri = uri, entity = instance.toJson(instanceFormat).toString())
258-
Try(Http(system).singleRequest(request)) match {
263+
//use generic name for startup, no id present at this point
264+
Try(Http(system).singleRequest(request.withHeaders(RawHeader("Authorization",s"Bearer ${AuthProvider.generateJwt(useGenericName = true)}")))) match {
259265
case Success(res) =>
260266
res
261267
case Failure(ex) =>

build.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ resolvers += Resolver.sonatypeRepo("snapshots")
2222
libraryDependencies += guice
2323
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
2424

25+
libraryDependencies += "com.pauldijou" %% "jwt-core" % "1.0.0"
26+
2527
// Akka dependencies
2628
libraryDependencies ++= Seq(
2729
"com.typesafe.akka" %% "akka-http-core" % "10.0.11",

0 commit comments

Comments
 (0)