-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1679 from dedis/work-be2-jharaxus-authentication-…
…message-response-handling Properly handle authentication message to complete popcha authentication
- Loading branch information
Showing
38 changed files
with
923 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 48 additions & 4 deletions
52
be2-scala/src/main/scala/ch/epfl/pop/authentication/GetRequestHandler.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,65 @@ | ||
package ch.epfl.pop.authentication | ||
|
||
import akka.http.scaladsl.model._ | ||
import akka.http.scaladsl.server | ||
import akka.http.scaladsl.server.Directives | ||
import akka.http.scaladsl.server.Directives.path | ||
import akka.http.scaladsl.server.Directives.{complete, pathPrefix} | ||
import akka.pattern.AskableActorRef | ||
import akka.util.Timeout | ||
import ch.epfl.pop.config.ServerConf | ||
import ch.epfl.pop.storage.SecurityModuleActor.{ReadRsaPublicKeyPem, ReadRsaPublicKeyPemAck} | ||
|
||
import java.util.concurrent.TimeUnit | ||
import scala.concurrent.Await | ||
import scala.util.Success | ||
|
||
/** Object to handle the http-get requests supported by the server | ||
*/ | ||
object GetRequestHandler { | ||
|
||
def buildRoutes(config: ServerConf): server.Route = { | ||
// Implicit for system actors | ||
implicit val timeout: Timeout = Timeout(1, TimeUnit.SECONDS) | ||
|
||
/** Build routes to handle the http-get requests supported by the server | ||
* @param config | ||
* server configuration to use | ||
* @param securityModuleActorRef | ||
* security module to use for secret keys | ||
* @return | ||
* a route to handle get requests | ||
*/ | ||
def buildRoutes(config: ServerConf, securityModuleActorRef: AskableActorRef): server.Route = { | ||
Directives.get { | ||
buildPathRoute(config.authenticationPath, Authenticate.buildRoute()) | ||
Directives.concat( | ||
buildPathRoute(config.authenticationPath, Authenticate.buildRoute()), | ||
buildPathRoute(config.publicKeyEndpoint, fetchPublicKey(securityModuleActorRef)) | ||
) | ||
} | ||
} | ||
|
||
private def buildPathRoute(pathName: String, route: server.Route): server.Route = { | ||
path(pathName) { | ||
pathPrefix(pathName) { | ||
route | ||
} | ||
} | ||
|
||
private def fetchPublicKey(securityModuleActorRef: AskableActorRef): server.Route = { | ||
complete { | ||
Await.ready(securityModuleActorRef ? ReadRsaPublicKeyPem(), timeout.duration).value match { | ||
case Some(Success(ReadRsaPublicKeyPemAck(publicKey))) => requestSuccess(publicKey) | ||
case Some(reply) => requestFailure("Server error", reply.toString) | ||
case None => requestFailure("Server error", "No response received from DB") | ||
} | ||
} | ||
} | ||
|
||
private def requestFailure(error: String, errorDescription: String): HttpResponse = { | ||
HttpResponse(status = StatusCodes.OK) | ||
.addAttribute(AttributeKey("error"), error) | ||
.addAttribute(AttributeKey("error_description"), errorDescription) | ||
} | ||
|
||
private def requestSuccess(response: String) = { | ||
HttpResponse(status = StatusCodes.OK, entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, response)) | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
be2-scala/src/main/scala/ch/epfl/pop/authentication/PopchaWebSocketResponseHandler.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package ch.epfl.pop.authentication | ||
|
||
import akka.actor.{ActorRef, ActorSystem} | ||
import akka.http.scaladsl.model.ws.{Message, TextMessage} | ||
import akka.http.scaladsl.server.Directives._ | ||
import akka.http.scaladsl.server._ | ||
import akka.stream.scaladsl.{Flow, Sink, Source} | ||
import akka.stream.{CompletionStrategy, OverflowStrategy} | ||
import akka.{Done, NotUsed} | ||
import ch.epfl.pop.config.ServerConf | ||
|
||
import scala.concurrent.{Future, Promise} | ||
|
||
/** This websocket handler receives the JWT from the PopchaHandler via websocket and forwards it to the client webpage connected via websocket as well. | ||
*/ | ||
object PopchaWebSocketResponseHandler { | ||
|
||
private val LISTENER_BUFFER_SIZE: Int = 256 | ||
|
||
private val socketsConnected: collection.mutable.Map[(String, String, String), ActorRef] = collection.mutable.Map() | ||
|
||
/** Builds a route to handle the websocket requests received | ||
* @param config | ||
* server configuration to use | ||
* @param system | ||
* actor system to use to spawn actors | ||
* @return | ||
* a route that handles the server's response websocket messages | ||
*/ | ||
def buildRoute(config: ServerConf)(implicit system: ActorSystem): Route = { | ||
path(config.responseEndpoint / Segment / "authentication" / Segment / Segment) { | ||
(laoId: String, clientId: String, nonce: String) => | ||
handleWebSocketMessages(handleMessage(laoId, clientId, nonce)) | ||
} | ||
} | ||
|
||
/** Handle a message received using its socket id (laoId, clientId, nonce): | ||
* - If it is the first connection on this socket id, the connection is handled as a listener (waiting for a message). | ||
* - If it is the second connection on this socket id, the connection is handled as a server sending messages to the listener waiting. | ||
*/ | ||
private def handleMessage(laoId: String, clientId: String, nonce: String)(implicit system: ActorSystem): Flow[Message, Message, Any] = { | ||
val socketId = (laoId, clientId, nonce) | ||
socketsConnected.get(socketId) match { | ||
case Some(listener) => handleMessageAsServer(listener, socketId) | ||
case None => handleMessageAsListener(socketId) | ||
} | ||
} | ||
|
||
private def handleMessageAsListener(socketId: (String, String, String)): Flow[Message, Message, Any] = { | ||
val dummySink = Sink.ignore | ||
val source: Source[TextMessage, NotUsed] = Source | ||
.actorRef( | ||
{ | ||
case Done => CompletionStrategy.immediately | ||
}, | ||
PartialFunction.empty, | ||
bufferSize = LISTENER_BUFFER_SIZE, | ||
overflowStrategy = OverflowStrategy.dropBuffer | ||
) | ||
.mapMaterializedValue(wsHandle => { | ||
socketsConnected.put(socketId, wsHandle) | ||
NotUsed | ||
}) | ||
Flow.fromSinkAndSourceCoupled(dummySink, source) | ||
} | ||
|
||
private def handleMessageAsServer(listenerRef: ActorRef, socketId: (String, String, String)): Flow[Message, Message, Any] = { | ||
val sink: Sink[Message, Future[Done]] = | ||
Sink.foreach { | ||
case message: TextMessage.Strict => | ||
listenerRef ! message | ||
listenerRef ! Done | ||
socketsConnected.remove(socketId) | ||
case _ => // ignore other message types | ||
} | ||
val dummySource: Source[Message, Promise[Option[Nothing]]] = Source.maybe | ||
Flow.fromSinkAndSourceCoupled(sink, dummySource) | ||
} | ||
} |
Oops, something went wrong.