Skip to content

Commit 12e10c6

Browse files
authored
Merge pull request #89 from pjfanning/softwaremill-pekko
Pekko HTTP Session
2 parents 8ff8681 + 426c24f commit 12e10c6

File tree

68 files changed

+6712
-18
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+6712
-18
lines changed

build.sbt

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import com.softwaremill.SbtSoftwareMillCommon.commonSmlBuildSettings
22
import com.softwaremill.Publish.ossPublishSettings
33

4-
val scala2_12 = "2.12.15"
5-
val scala2_13 = "2.13.8"
4+
val scala2_12 = "2.12.18"
5+
val scala2_13 = "2.13.11"
6+
val scala3 = "3.3.0"
67
val scala2 = List(scala2_12, scala2_13)
8+
val scala2And3 = List(scala2_12, scala2_13, scala3)
79

810
lazy val commonSettings = commonSmlBuildSettings ++ ossPublishSettings ++ Seq(
911
organization := "com.softwaremill.akka-http-session",
@@ -16,12 +18,12 @@ val json4sVersion = "4.0.4"
1618
val akkaStreamsProvided = "com.typesafe.akka" %% "akka-stream" % akkaStreamsVersion % "provided"
1719
val akkaStreamsTestkit = "com.typesafe.akka" %% "akka-stream-testkit" % akkaStreamsVersion % "test"
1820

19-
val scalaTest = "org.scalatest" %% "scalatest" % "3.2.11" % "test"
21+
val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" % "test"
2022

2123
lazy val rootProject = (project in file("."))
22-
.settings(commonSettings: _*)
23-
.settings(publish / skip := true, name := "akka-http-session", scalaVersion := scala2_13)
24-
.aggregate(core.projectRefs ++ jwt.projectRefs ++ example.projectRefs ++ javaTests.projectRefs: _*)
24+
.settings(publish / skip := true, name := "akka-http-session-root", scalaVersion := scala2_13)
25+
.aggregate(core.projectRefs ++ jwt.projectRefs ++ example.projectRefs ++ javaTests.projectRefs ++
26+
pekkoCore.projectRefs ++ pekkoJwt.projectRefs ++ pekkoExample.projectRefs ++ pekkoJavaTests.projectRefs: _*)
2527

2628
lazy val core = (projectMatrix in file("core"))
2729
.settings(commonSettings: _*)
@@ -88,3 +90,85 @@ lazy val javaTests = (projectMatrix in file("javaTests"))
8890
)
8991
.jvmPlatform(scalaVersions = scala2)
9092
.dependsOn(core, jwt)
93+
94+
// Pekko build
95+
96+
lazy val pekkoCommonSettings = commonSmlBuildSettings ++ ossPublishSettings ++ Seq(
97+
organization := "com.softwaremill.pekko-http-session",
98+
versionScheme := Some("early-semver")
99+
)
100+
101+
val pekkoHttpVersion = "1.0.0"
102+
val pekkoStreamsVersion = "1.0.1"
103+
104+
val pekkoStreamsProvided = "org.apache.pekko" %% "pekko-stream" % pekkoStreamsVersion % "provided"
105+
val pekkoStreamsTestkit = "org.apache.pekko" %% "pekko-stream-testkit" % pekkoStreamsVersion % "test"
106+
val scalaJava8CompatVersion = "1.0.2"
107+
108+
lazy val pekkoCore = (projectMatrix in file("pekko-http-session/core"))
109+
.settings(pekkoCommonSettings: _*)
110+
.settings(
111+
name := "core",
112+
libraryDependencies ++= Seq(
113+
"org.apache.pekko" %% "pekko-http" % pekkoHttpVersion,
114+
"org.scala-lang.modules" %% "scala-java8-compat" % scalaJava8CompatVersion,
115+
pekkoStreamsProvided,
116+
"org.apache.pekko" %% "pekko-http-testkit" % pekkoHttpVersion % "test",
117+
pekkoStreamsTestkit,
118+
"org.scalacheck" %% "scalacheck" % "1.15.4" % "test",
119+
scalaTest
120+
)
121+
)
122+
.jvmPlatform(scalaVersions = scala2And3)
123+
124+
lazy val pekkoJwt = (projectMatrix in file("pekko-http-session/jwt"))
125+
.settings(pekkoCommonSettings: _*)
126+
.settings(
127+
name := "jwt",
128+
libraryDependencies ++= Seq(
129+
"org.json4s" %% "json4s-jackson" % json4sVersion,
130+
"org.json4s" %% "json4s-ast" % json4sVersion,
131+
"org.json4s" %% "json4s-core" % json4sVersion,
132+
pekkoStreamsProvided,
133+
scalaTest
134+
),
135+
// generating docs for 2.13 causes an error: "not found: type DefaultFormats$"
136+
Compile / doc / sources := Seq.empty
137+
)
138+
.jvmPlatform(scalaVersions = scala2And3)
139+
.dependsOn(pekkoCore)
140+
141+
lazy val pekkoExample = (projectMatrix in file("pekko-http-session/example"))
142+
.settings(pekkoCommonSettings: _*)
143+
.settings(
144+
publishArtifact := false,
145+
libraryDependencies ++= Seq(
146+
pekkoStreamsProvided,
147+
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4",
148+
"ch.qos.logback" % "logback-classic" % "1.2.12",
149+
"org.json4s" %% "json4s-ext" % json4sVersion
150+
)
151+
)
152+
.jvmPlatform(scalaVersions = scala2And3)
153+
.dependsOn(pekkoCore, pekkoJwt)
154+
155+
lazy val pekkoJavaTests = (projectMatrix in file("pekko-http-session/javaTests"))
156+
.settings(pekkoCommonSettings: _*)
157+
.settings(
158+
name := "javaTests",
159+
Test / testOptions := Seq(Tests.Argument(TestFrameworks.JUnit, "-a")), // required for javadsl JUnit tests
160+
crossPaths := false, // https://github.com/sbt/junit-interface/issues/35
161+
publishArtifact := false,
162+
libraryDependencies ++= Seq(
163+
pekkoStreamsProvided,
164+
"org.apache.pekko" %% "pekko-http" % pekkoHttpVersion,
165+
"org.scala-lang.modules" %% "scala-java8-compat" % scalaJava8CompatVersion,
166+
"org.apache.pekko" %% "pekko-http-testkit" % pekkoHttpVersion % "test",
167+
pekkoStreamsTestkit,
168+
"junit" % "junit" % "4.13.2" % "test",
169+
"com.github.sbt" % "junit-interface" % "0.13.3" % "test",
170+
scalaTest
171+
)
172+
)
173+
.jvmPlatform(scalaVersions = scala2And3)
174+
.dependsOn(pekkoCore, pekkoJwt)

core/src/test/scala/com/softwaremill/session/CsrfDirectivesTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class CsrfDirectivesTest extends AnyFlatSpec with ScalatestRouteTest with Matche
4343
responseAs[String] should be("ok")
4444

4545
val csrfCookieOption = header[`Set-Cookie`]
46-
csrfCookieOption should be('defined)
46+
csrfCookieOption shouldBe defined
4747
val Some(csrfCookie) = csrfCookieOption
4848

4949
csrfCookie.cookie.name should be(cookieName)

core/src/test/scala/com/softwaremill/session/OneOffTest.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class OneOffTest extends AnyFlatSpec with ScalatestRouteTest with Matchers with
5555
"Using cookies" should "set the correct session cookie name" in {
5656
Get("/set") ~> createRoutes(TestUsingCookies) ~> check {
5757
val sessionCookieOption = header[`Set-Cookie`]
58-
sessionCookieOption should be('defined)
58+
sessionCookieOption shouldBe defined
5959
val Some(sessionCookie) = sessionCookieOption
6060

6161
sessionCookie.cookie.name should be(TestUsingCookies.sessionCookieName)
@@ -71,7 +71,7 @@ class OneOffTest extends AnyFlatSpec with ScalatestRouteTest with Matchers with
7171
responseAs[String] should be("ok")
7272

7373
val sessionOption = using.getSession
74-
sessionOption should be('defined)
74+
sessionOption shouldBe defined
7575

7676
using.isSessionExpired should be(false)
7777
}
@@ -188,7 +188,7 @@ class OneOffTest extends AnyFlatSpec with ScalatestRouteTest with Matchers with
188188
val legacySession = Legacy.encodeV0_5_1(data, now, sessionConfig)
189189

190190
Get("/getReq") ~> addHeader(using.setSessionHeader(legacySession)) ~> routes(manager_tokenMigrationFromV0_5_1) ~> check {
191-
using.getSession should be('defined)
191+
using.getSession shouldBe defined
192192
responseAs[String] should be(data.toString)
193193
}
194194
}
@@ -213,7 +213,7 @@ class OneOffTest extends AnyFlatSpec with ScalatestRouteTest with Matchers with
213213
val legacySession = Legacy.encodeV0_5_2(data, now, sessionConfig)
214214

215215
Get("/getReq") ~> addHeader(using.setSessionHeader(legacySession)) ~> routes(manager_tokenMigrationFromV0_5_2) ~> check {
216-
using.getSession should be('defined)
216+
using.getSession shouldBe defined
217217
responseAs[String] should be(data.toString)
218218
}
219219
}

core/src/test/scala/com/softwaremill/session/RefreshableTest.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ class RefreshableTest extends AnyFlatSpec with ScalatestRouteTest with Matchers
6464
Get("/set") ~> routes ~> check {
6565
responseAs[String] should be("ok")
6666

67-
using.getSession should be('defined)
67+
using.getSession shouldBe defined
6868
using.countSessionHeaders should be(1)
69-
using.getRefreshToken should be('defined)
69+
using.getRefreshToken shouldBe defined
7070
using.countRefreshTokenHeaders should be(1)
7171
}
7272
}
@@ -120,7 +120,7 @@ class RefreshableTest extends AnyFlatSpec with ScalatestRouteTest with Matchers
120120
Get("/set") ~> routes ~> check {
121121
val Some(token1) = using.getRefreshToken
122122
val session1 = using.getSession
123-
session1 should be('defined)
123+
session1 shouldBe defined
124124

125125
Get("/getOpt") ~>
126126
addHeader(using.setRefreshTokenHeader(token1)) ~>
@@ -129,7 +129,7 @@ class RefreshableTest extends AnyFlatSpec with ScalatestRouteTest with Matchers
129129
using.countSessionHeaders should be(1)
130130
using.countRefreshTokenHeaders should be(1)
131131
val session2 = using.getSession
132-
session2 should be('defined)
132+
session2 shouldBe defined
133133
session2 should not be (session1)
134134
}
135135
}
@@ -275,7 +275,7 @@ class RefreshableTest extends AnyFlatSpec with ScalatestRouteTest with Matchers
275275

276276
// new token should be generated
277277
session1 should not be (session3)
278-
token3Opt should be('defined)
278+
token3Opt shouldBe defined
279279
}
280280
}
281281
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.softwaremill.pekkohttpsession.javadsl
2+
3+
import com.softwaremill.pekkohttpsession
4+
import com.softwaremill.pekkohttpsession.CsrfCheckMode
5+
6+
import java.util.function.Supplier
7+
import org.apache.pekko.http.javadsl.server.Route
8+
import org.apache.pekko.http.javadsl.server.directives.RouteAdapter
9+
10+
/**
11+
* Java alternative for com.softwaremill.pekkohttpsession.CsrfDirectives
12+
*/
13+
trait CsrfDirectives {
14+
15+
def hmacTokenCsrfProtection[T](checkMode: CsrfCheckMode[T], inner: Supplier[Route]): Route = RouteAdapter {
16+
pekkohttpsession.CsrfDirectives.hmacTokenCsrfProtection(checkMode) {
17+
inner.get.asInstanceOf[RouteAdapter].delegate
18+
}
19+
}
20+
21+
/**
22+
* @deprecated as of release 0.6.1, replaced by {@link #hmacTokensCsrfProtection()}
23+
*/
24+
def randomTokenCsrfProtection[T](checkMode: CsrfCheckMode[T], inner: Supplier[Route]): Route =
25+
hmacTokenCsrfProtection(checkMode, inner)
26+
27+
def setNewCsrfToken[T](checkMode: CsrfCheckMode[T], inner: Supplier[Route]): Route = RouteAdapter {
28+
pekkohttpsession.CsrfDirectives.setNewCsrfToken(checkMode) {
29+
inner.get.asInstanceOf[RouteAdapter].delegate
30+
}
31+
}
32+
33+
}
34+
35+
object CsrfDirectives extends CsrfDirectives
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.softwaremill.pekkohttpsession.javadsl;
2+
3+
import org.apache.pekko.http.javadsl.server.AllDirectives;
4+
import org.apache.pekko.http.javadsl.server.Route;
5+
import com.softwaremill.pekkohttpsession.CsrfCheckMode;
6+
import com.softwaremill.pekkohttpsession.GetSessionTransport;
7+
import com.softwaremill.pekkohttpsession.SessionContinuity;
8+
import com.softwaremill.pekkohttpsession.SessionManager;
9+
import com.softwaremill.pekkohttpsession.SessionResult;
10+
import com.softwaremill.pekkohttpsession.SetSessionTransport;
11+
12+
import java.util.Optional;
13+
import java.util.function.Function;
14+
import java.util.function.Supplier;
15+
16+
public class HttpSessionAwareDirectives<T> extends AllDirectives {
17+
18+
private final SessionManager<T> sessionManager;
19+
20+
public HttpSessionAwareDirectives(SessionManager<T> sessionManager) {
21+
this.sessionManager = sessionManager;
22+
}
23+
24+
public Route session(SessionContinuity sc, GetSessionTransport st, Function<SessionResult<T>, Route> continuity) {
25+
return SessionDirectives$.MODULE$.session(sc, st, continuity);
26+
}
27+
28+
public Route setSession(SessionContinuity sc, SetSessionTransport st, T session, Supplier<Route> continuity) {
29+
return SessionDirectives$.MODULE$.setSession(sc, st, session, continuity);
30+
}
31+
32+
public Route optionalSession(SessionContinuity sc, SetSessionTransport st, Function<Optional<T>, Route> continuity) {
33+
return SessionDirectives$.MODULE$.optionalSession(sc, st, continuity);
34+
}
35+
36+
public Route requiredSession(SessionContinuity<T> sc, SetSessionTransport st, Function<T, Route> continuity) {
37+
return SessionDirectives$.MODULE$.requiredSession(sc, st, continuity);
38+
}
39+
40+
public Route touchRequiredSession(SessionContinuity<T> sc, SetSessionTransport st, Function<T, Route> continuity) {
41+
return SessionDirectives$.MODULE$.touchRequiredSession(sc, st, continuity);
42+
}
43+
44+
public Route invalidateSession(SessionContinuity<T> sc, SetSessionTransport st, Supplier<Route> continuity) {
45+
return SessionDirectives$.MODULE$.invalidateSession(sc, st, continuity);
46+
}
47+
48+
public Route setNewCsrfToken(CsrfCheckMode<T> checkHeader, Supplier<Route> continuity) {
49+
return CsrfDirectives$.MODULE$.setNewCsrfToken(checkHeader, continuity);
50+
}
51+
52+
public Route randomTokenCsrfProtection(CsrfCheckMode<T> checkHeader, Supplier<Route> continuity) {
53+
return CsrfDirectives$.MODULE$.randomTokenCsrfProtection(checkHeader, continuity);
54+
}
55+
56+
public SessionManager<T> getSessionManager() {
57+
return sessionManager;
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.softwaremill.pekkohttpsession.javadsl
2+
3+
/**
4+
* Can't use the trait com.softwaremill.pekkohttpsession.InMemoryRefreshTokenStorage in Java code, hence this wrapper
5+
* http://stackoverflow.com/questions/7637752/using-scala-traits-with-implemented-methods-in-java
6+
*/
7+
abstract class InMemoryRefreshTokenStorage[T]() extends com.softwaremill.pekkohttpsession.InMemoryRefreshTokenStorage[T]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.softwaremill.pekkohttpsession.javadsl
2+
3+
import com.softwaremill.pekkohttpsession
4+
import com.softwaremill.pekkohttpsession.{GetSessionTransport, OneOffSessionDirectives, RefreshableSessionDirectives, SessionContinuity, SessionResult, SetSessionTransport}
5+
6+
import java.util.Optional
7+
import java.util.function.Supplier
8+
import org.apache.pekko.http.javadsl.server.Route
9+
import org.apache.pekko.http.javadsl.server.directives.RouteAdapter
10+
11+
import scala.compat.java8.OptionConverters._
12+
13+
/**
14+
* Java alternative for com.softwaremill.pekkohttpsession.SessionDirectives
15+
*/
16+
trait SessionDirectives extends OneOffSessionDirectives with RefreshableSessionDirectives {
17+
18+
def session[T](sc: SessionContinuity[T], st: GetSessionTransport, inner: java.util.function.Function[SessionResult[T], Route]): Route = RouteAdapter {
19+
pekkohttpsession.SessionDirectives.session(sc, st) { sessionResult =>
20+
inner.apply(sessionResult).asInstanceOf[RouteAdapter].delegate
21+
}
22+
}
23+
24+
def setSession[T](sc: SessionContinuity[T], st: SetSessionTransport, v: T, inner: Supplier[Route]): Route = RouteAdapter {
25+
pekkohttpsession.SessionDirectives.setSession(sc, st, v) {
26+
inner.get.asInstanceOf[RouteAdapter].delegate
27+
}
28+
}
29+
30+
def invalidateSession[T](sc: SessionContinuity[T], st: GetSessionTransport, inner: Supplier[Route]): Route = RouteAdapter {
31+
pekkohttpsession.SessionDirectives.invalidateSession(sc, st) {
32+
inner.get.asInstanceOf[RouteAdapter].delegate
33+
}
34+
}
35+
36+
def optionalSession[T](sc: SessionContinuity[T], st: GetSessionTransport, inner: java.util.function.Function[Optional[T], Route]): Route = RouteAdapter {
37+
pekkohttpsession.SessionDirectives.optionalSession(sc, st) { session =>
38+
inner.apply(session.asJava).asInstanceOf[RouteAdapter].delegate
39+
}
40+
}
41+
42+
def requiredSession[T](sc: SessionContinuity[T], st: GetSessionTransport, inner: java.util.function.Function[T, Route]): Route = RouteAdapter {
43+
pekkohttpsession.SessionDirectives.requiredSession(sc, st) { session =>
44+
inner.apply(session).asInstanceOf[RouteAdapter].delegate
45+
}
46+
}
47+
48+
def touchRequiredSession[T](sc: SessionContinuity[T], st: GetSessionTransport, inner: java.util.function.Function[T, Route]): Route = RouteAdapter {
49+
pekkohttpsession.SessionDirectives.touchRequiredSession(sc, st) { session =>
50+
inner.apply(session).asInstanceOf[RouteAdapter].delegate
51+
}
52+
}
53+
54+
}
55+
56+
object SessionDirectives extends SessionDirectives
57+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.softwaremill.pekkohttpsession.javadsl;
2+
3+
import com.softwaremill.pekkohttpsession.MultiValueSessionSerializer;
4+
import com.softwaremill.pekkohttpsession.SessionSerializer;
5+
import com.softwaremill.pekkohttpsession.SessionSerializer$;
6+
import com.softwaremill.pekkohttpsession.converters.MapConverters;
7+
import scala.collection.JavaConverters;
8+
import scala.compat.java8.JFunction0;
9+
import scala.compat.java8.JFunction1;
10+
import scala.util.Try;
11+
12+
import java.util.Map;
13+
14+
/**
15+
* Wrapper for session serializers in com.softwaremill.pekkohttpsession.SessionSerializer
16+
*/
17+
public final class SessionSerializers {
18+
19+
public static final SessionSerializer<String, String> StringToStringSessionSerializer = SessionSerializer$.MODULE$.stringToStringSessionSerializer();
20+
public static final SessionSerializer<Integer, String> IntToStringSessionSerializer = (SessionSerializer<Integer, String>) (SessionSerializer) SessionSerializer$.MODULE$.intToStringSessionSerializer();
21+
public static final SessionSerializer<Long, String> LongToStringSessionSerializer = (SessionSerializer<Long, String>) (SessionSerializer) SessionSerializer$.MODULE$.longToStringSessionSerializer();
22+
public static final SessionSerializer<Float, String> FloatToStringSessionSerializer = (SessionSerializer<Float, String>) (SessionSerializer) SessionSerializer$.MODULE$.floatToStringSessionSerializer();
23+
public static final SessionSerializer<Double, String> DoubleToStringSessionSerializer = (SessionSerializer<Double, String>) (SessionSerializer) SessionSerializer$.MODULE$.doubleToStringSessionSerializer();
24+
25+
public static final SessionSerializer<Map<String, String>, String> MapToStringSessionSerializer = new MultiValueSessionSerializer<>(
26+
(JFunction1<Map<String, String>, scala.collection.immutable.Map<String, String>>) m -> MapConverters.toImmutableMap(m),
27+
(JFunction1<scala.collection.immutable.Map<String, String>, Try<Map<String, String>>>) v1 ->
28+
Try.apply((JFunction0<Map<String, String>>) () -> JavaConverters.mapAsJavaMapConverter(v1).asJava())
29+
);
30+
31+
private SessionSerializers() {
32+
}
33+
34+
}

0 commit comments

Comments
 (0)