Skip to content

Commit 5248f63

Browse files
committed
finalize sofwaremill akka-http-session evolutions
1 parent 7ced522 commit 5248f63

File tree

8 files changed

+105
-43
lines changed

8 files changed

+105
-43
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ThisBuild / organization := "app.softnetwork"
3030

3131
name := "generic-persistence-api"
3232

33-
ThisBuild / version := "0.3.2.1"
33+
ThisBuild / version := "0.3.2.2"
3434

3535
ThisBuild / scalaVersion := "2.12.11"
3636

session/core/src/main/scala/com/softwaremill/session/Completion.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import scala.concurrent.{Await, Future}
44
import scala.concurrent.duration.{Duration, DurationInt, FiniteDuration}
55
import scala.util.{Failure, Success, Try}
66

7-
import scala.language.implicitConversions
8-
97
trait Completion {
108

119
/** maximum wait time, which may be negative (no waiting is done),

session/core/src/main/scala/com/softwaremill/session/CsrfEndpoints.scala

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,32 @@ trait CsrfEndpoints {
3535
body
3636
}
3737

38-
def setNewCsrfToken[T](
38+
def setNewCsrfToken[T, SECURITY_INPUT, PRINCIPAL, SECURITY_OUTPUT](
3939
checkMode: TapirCsrfCheckMode[T]
40-
): PartialServerEndpointWithSecurityOutput[Unit, Unit, Unit, Unit, Option[
41-
CookieValueWithMeta
42-
], Unit, Any, Future] =
43-
checkMode.setNewCsrfToken()
40+
)(
41+
body: => PartialServerEndpointWithSecurityOutput[
42+
SECURITY_INPUT,
43+
PRINCIPAL,
44+
Unit,
45+
Unit,
46+
SECURITY_OUTPUT,
47+
Unit,
48+
Any,
49+
Future
50+
]
51+
): PartialServerEndpointWithSecurityOutput[
52+
SECURITY_INPUT,
53+
PRINCIPAL,
54+
Unit,
55+
Unit,
56+
(SECURITY_OUTPUT, Option[CookieValueWithMeta]),
57+
Unit,
58+
Any,
59+
Future
60+
] =
61+
checkMode.setNewCsrfToken {
62+
body
63+
}
4464
}
4565

4666
object CsrfEndpoints extends CsrfEndpoints

session/core/src/main/scala/com/softwaremill/session/SessionEndpoints.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ trait SessionEndpoints {
2323
], Unit, Unit, Seq[Option[String]], Unit, Any, Future] =
2424
sc.setSession(st)(endpoint)
2525

26+
def setSessionWithAuth[T, A](sc: TapirSessionContinuity[T], st: SetSessionTransport)(
27+
auth: EndpointInput.Auth[A, EndpointInput.AuthType.Http]
28+
)(implicit
29+
f: A => Option[T]
30+
): PartialServerEndpointWithSecurityOutput[(A, Seq[Option[String]]), Option[T], Unit, Unit, Seq[
31+
Option[String]
32+
], Unit, Any, Future] =
33+
setSession(sc, st) {
34+
endpoint.securityIn(auth)
35+
}
36+
2637
/** Read a session from the session cookie, wrapped in [[SessionResult]] describing the possible
2738
* success/failure outcomes.
2839
*

session/core/src/main/scala/com/softwaremill/session/TapirCsrf.scala

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,37 @@ private[session] trait TapirCsrf[T] { _: CsrfCheck =>
2828
manager.config.csrfSubmittedName
2929
).description("read csrf token as header")
3030

31-
def setNewCsrfToken(): PartialServerEndpointWithSecurityOutput[Unit, Unit, Unit, Unit, Option[
32-
CookieValueWithMeta
33-
], Unit, Any, Future] =
34-
endpoint
31+
def setNewCsrfToken[SECURITY_INPUT, PRINCIPAL, SECURITY_OUTPUT](
32+
body: => PartialServerEndpointWithSecurityOutput[
33+
SECURITY_INPUT,
34+
PRINCIPAL,
35+
Unit,
36+
Unit,
37+
SECURITY_OUTPUT,
38+
Unit,
39+
Any,
40+
Future
41+
]
42+
): PartialServerEndpointWithSecurityOutput[
43+
SECURITY_INPUT,
44+
PRINCIPAL,
45+
Unit,
46+
Unit,
47+
(SECURITY_OUTPUT, Option[CookieValueWithMeta]),
48+
Unit,
49+
Any,
50+
Future
51+
] =
52+
body.endpoint
53+
.out(body.securityOutput)
3554
.out(csrfCookie)
36-
.serverSecurityLogicSuccessWithOutput[Unit, Future](_ =>
37-
Future.successful((Some(manager.csrfManager.createCookie().valueWithMeta), ()))
38-
)
55+
.serverSecurityLogicWithOutput { inputs =>
56+
body.securityLogic(new FutureMonad())(inputs).map {
57+
case Left(l) => Left(l)
58+
case Right(r) =>
59+
Right(((r._1, Some(manager.csrfManager.createCookie().valueWithMeta)), r._2))
60+
}
61+
}
3962

4063
/** Protects against CSRF attacks using a double-submit cookie. The cookie will be set on any
4164
* `GET` request which doesn't have the token set in the header. For all other requests, the

session/core/src/main/scala/com/softwaremill/session/TapirEndpoints.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.softwaremill.session
22

33
import sttp.model.Method
44
import sttp.model.headers.CookieValueWithMeta
5+
import sttp.tapir.{Endpoint, EndpointInput}
56
import sttp.tapir.server.PartialServerEndpointWithSecurityOutput
67

78
import scala.concurrent.Future
@@ -44,6 +45,33 @@ trait TapirEndpoints extends SessionEndpoints with CsrfEndpoints {
4445
optionalSession(sc, st)
4546
}
4647

48+
def setNewCsrfTokenWithSession[T, INPUT](
49+
sc: TapirSessionContinuity[T],
50+
st: SetSessionTransport,
51+
checkMode: TapirCsrfCheckMode[T]
52+
)(endpoint: => Endpoint[INPUT, Unit, Unit, Unit, Any])(implicit
53+
f: INPUT => Option[T]
54+
): PartialServerEndpointWithSecurityOutput[(INPUT, Seq[Option[String]]), Option[
55+
T
56+
], Unit, Unit, (Seq[Option[String]], Option[CookieValueWithMeta]), Unit, Any, Future] =
57+
setNewCsrfToken(checkMode) {
58+
setSession(sc, st) {
59+
endpoint
60+
}
61+
}
62+
63+
def setNewCsrfTokenWithAuth[T, A](
64+
sc: TapirSessionContinuity[T],
65+
st: SetSessionTransport,
66+
checkMode: TapirCsrfCheckMode[T]
67+
)(auth: EndpointInput.Auth[A, EndpointInput.AuthType.Http])(implicit
68+
f: A => Option[T]
69+
): PartialServerEndpointWithSecurityOutput[(A, Seq[Option[String]]), Option[
70+
T
71+
], Unit, Unit, (Seq[Option[String]], Option[CookieValueWithMeta]), Unit, Any, Future] =
72+
setNewCsrfToken(checkMode) {
73+
setSessionWithAuth(sc, st)(auth)
74+
}
4775
}
4876

4977
object TapirEndpoints extends TapirEndpoints

session/core/src/main/scala/com/softwaremill/session/TapirImplicits.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import sttp.model.headers.Cookie.SameSite
77
import sttp.model.headers.{CookieValueWithMeta, CookieWithMeta}
88

99
import java.time.Instant
10-
import scala.language.implicitConversions
1110

1211
object TapirImplicits {
1312

session/testkit/src/main/scala/app/softnetwork/session/scalatest/SessionEndpointsRoute.scala

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ import app.softnetwork.session.service._
77
import com.softwaremill.session.{SessionEndpoints => _, _}
88
import org.softnetwork.session.model.Session
99
import sttp.model.StatusCode
10-
import sttp.model.headers.CookieValueWithMeta
1110
import sttp.tapir._
1211
import sttp.tapir.generic.auto._
1312
import sttp.tapir.json.json4s.jsonBody
14-
import sttp.tapir.server.{PartialServerEndpointWithSecurityOutput, ServerEndpoint}
13+
import sttp.tapir.server.ServerEndpoint
1514

1615
import scala.concurrent.{ExecutionContext, Future}
1716

18-
trait SessionEndpointsRoute extends ApiEndpoint with RouteConcatenation {
17+
trait SessionEndpointsRoute extends TapirEndpoints with ApiEndpoint with RouteConcatenation {
1918

2019
import Session._
2120

@@ -49,29 +48,15 @@ trait SessionEndpointsRoute extends ApiEndpoint with RouteConcatenation {
4948
def checkMode: TapirCsrfCheckMode[Session] = sessionEndpoints.checkMode
5049

5150
val createSessionEndpoint: ServerEndpoint[Any, Future] = {
52-
import TapirImplicits._
53-
sessionEndpoints
54-
.setSession(sc, st) {
55-
endpoint.securityIn(jsonBody[CreateSession]).description("the session to create")
56-
}
57-
.post
51+
setNewCsrfTokenWithSession(sc, st, checkMode) {
52+
endpoint.securityIn(jsonBody[CreateSession].description("the session to create"))
53+
}.post
5854
.in("session")
59-
.out(
60-
setCookieOpt(sessionEndpoints.manager.config.csrfCookieConfig.name)
61-
.description("set csrf token as cookie")
62-
)
63-
.serverLogic(_ =>
64-
_ =>
65-
Future.successful(
66-
Right(Some(sessionEndpoints.manager.csrfManager.createCookie().valueWithMeta))
67-
)
68-
)
55+
.serverLogicSuccess(_ => _ => Future.successful(()))
6956
}
7057

7158
val retrieveSessionEndpoint: ServerEndpoint[Any, Future] =
72-
sessionEndpoints
73-
.antiCsrfWithRequiredSession(sc, st, checkMode)
74-
.get
59+
antiCsrfWithRequiredSession(sc, st, checkMode).get
7560
.in("session")
7661
.out(
7762
oneOf[BusinessError](
@@ -84,11 +69,9 @@ trait SessionEndpointsRoute extends ApiEndpoint with RouteConcatenation {
8469
.serverLogic(_ => _ => Future.successful(Right(NotFound))) // simulate an error
8570

8671
val invalidateSessionEndpoint: ServerEndpoint[Any, Future] =
87-
sessionEndpoints
88-
.invalidateSession(sc, gt)(
89-
sessionEndpoints.antiCsrfWithRequiredSession(sc, st, checkMode)
90-
)
91-
.delete
72+
invalidateSession(sc, gt)(
73+
antiCsrfWithRequiredSession(sc, st, checkMode)
74+
).delete
9275
.in("session")
9376
.serverLogic(_ => _ => Future.successful(Right()))
9477

0 commit comments

Comments
 (0)