Skip to content

Commit

Permalink
ISSUE-1240 Use JMAPExtensionConfiguration to handle ticket IP validat…
Browse files Browse the repository at this point in the history
…ion config
  • Loading branch information
quantranhong1999 authored and vttranlina committed Oct 29, 2024
1 parent fa9d23e commit 9d1579d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.linagora.tmail.james.jmap

import com.linagora.tmail.james.jmap.JMAPExtensionConfiguration.PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT
import com.linagora.tmail.james.jmap.JMAPExtensionConfiguration.{PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT, TICKET_IP_VALIDATION_ENABLED}
import eu.timepit.refined
import org.apache.commons.configuration2.Configuration
import org.apache.james.core.MailAddress
Expand All @@ -12,21 +12,26 @@ import scala.util.{Failure, Success, Try}
object JMAPExtensionConfiguration {
val PUBLIC_ASSET_TOTAL_SIZE_LIMIT_PROPERTY: String = "public.asset.total.size"
val PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT: PublicAssetTotalSizeLimit = PublicAssetTotalSizeLimit.of(Size.of(20L, Size.Unit.M)).get
val TICKET_IP_VALIDATION_PROPERTY: String = "authentication.strategy.rfc8621.tickets.ip.validation.enabled"
val TICKET_IP_VALIDATION_ENABLED: TicketIpValidationEnable = TicketIpValidationEnable(true)

val SUPPORT_MAIL_ADDRESS_PROPERTY: String = "support.mail.address"

def from(configuration: Configuration): JMAPExtensionConfiguration = {
val publicAssetTotalSizeLimit: PublicAssetTotalSizeLimit = Option(configuration.getString(PUBLIC_ASSET_TOTAL_SIZE_LIMIT_PROPERTY, null))
.map(Size.parse)
.map(PublicAssetTotalSizeLimit.of(_).get)
.getOrElse(PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT)

val supportMailAddressOpt: Option[MailAddress] =
Option(configuration.getString(SUPPORT_MAIL_ADDRESS_PROPERTY, null))
.map(s => new MailAddress(s))

JMAPExtensionConfiguration(
publicAssetTotalSizeLimit = Option(configuration.getString(PUBLIC_ASSET_TOTAL_SIZE_LIMIT_PROPERTY, null))
.map(Size.parse)
.map(PublicAssetTotalSizeLimit.of(_).get)
.getOrElse(PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT),
supportMailAddressOpt
)
val ticketIpValidationEnable: TicketIpValidationEnable = Option(configuration.getBoolean(TICKET_IP_VALIDATION_PROPERTY, null))
.map(TicketIpValidationEnable(_))
.getOrElse(TICKET_IP_VALIDATION_ENABLED)

JMAPExtensionConfiguration(publicAssetTotalSizeLimit, supportMailAddressOpt, ticketIpValidationEnable)
}
}

Expand All @@ -37,8 +42,9 @@ object PublicAssetTotalSizeLimit {
}
}

case class JMAPExtensionConfiguration(publicAssetTotalSizeLimit: PublicAssetTotalSizeLimit = JMAPExtensionConfiguration.PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT,
supportMailAddress: Option[MailAddress] = Option.empty) {
case class JMAPExtensionConfiguration(publicAssetTotalSizeLimit: PublicAssetTotalSizeLimit = PUBLIC_ASSET_TOTAL_SIZE_LIMIT_DEFAULT,
supportMailAddress: Option[MailAddress] = Option.empty,
ticketIpValidationEnable: TicketIpValidationEnable = TICKET_IP_VALIDATION_ENABLED) {
def this(publicAssetTotalSizeLimit: PublicAssetTotalSizeLimit) = {
this(publicAssetTotalSizeLimit, Option.empty)
}
Expand All @@ -55,3 +61,5 @@ case class JMAPExtensionConfiguration(publicAssetTotalSizeLimit: PublicAssetTota
case class PublicAssetTotalSizeLimit(value: UnsignedInt) {
def asLong(): Long = value.value
}

case class TicketIpValidationEnable(value: Boolean)
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.linagora.tmail.james.jmap.ticket

import java.io.FileNotFoundException
import java.net.InetAddress
import java.time.{Clock, ZonedDateTime}
import java.util.UUID

import com.linagora.tmail.james.jmap.ticket.TicketManager.extractIpValidationEnableConfig
import com.linagora.tmail.james.jmap.JMAPExtensionConfiguration
import jakarta.inject.Inject
import org.apache.james.core.Username
import org.apache.james.jmap.core.UTCDate
import org.apache.james.utils.PropertiesProvider
import reactor.core.scala.publisher.SMono

import scala.collection.mutable
Expand All @@ -33,21 +31,9 @@ case class Ticket(clientAddress: InetAddress,

object TicketManager {
private val validity: java.time.Duration = java.time.Duration.ofMinutes(1)
private val ipValidationEnableProperty: String = "authentication.strategy.rfc8621.tickets.ip.validation.enabled"
private val ipValidationEnabled: Boolean = true

def extractIpValidationEnableConfig(propertiesProvider: PropertiesProvider): Boolean =
try {
Option(propertiesProvider.getConfiguration("jmap"))
.map(config => config.getBoolean(ipValidationEnableProperty, ipValidationEnabled))
.getOrElse(ipValidationEnabled)
} catch {
case _: FileNotFoundException => ipValidationEnabled
}
}

class TicketManager @Inject() (clock: Clock, ticketStore: TicketStore, propertiesProvider: PropertiesProvider) {
private val ipValidationEnabled: Boolean = extractIpValidationEnableConfig(propertiesProvider)
class TicketManager @Inject() (clock: Clock, ticketStore: TicketStore, jmapExtensionConfiguration: JMAPExtensionConfiguration) {

def generate(username: Username, remoteAddress: InetAddress): SMono[Ticket] = {
val now = ZonedDateTime.now(clock)
Expand All @@ -73,7 +59,7 @@ class TicketManager @Inject() (clock: Clock, ticketStore: TicketStore, propertie
.switchIfEmpty(SMono.error(ForbiddenException()))

private def validateIpIfNeeded(ip: InetAddress, ticket: Ticket): Boolean =
if (ipValidationEnabled) {
if (jmapExtensionConfiguration.ticketIpValidationEnable.value) {
ticket.clientAddress.equals(ip)
} else {
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.linagora.tmail.james.jmap.ticket
import java.net.InetAddress
import java.time.ZonedDateTime

import org.apache.commons.configuration2.PropertiesConfiguration
import org.apache.james.FakePropertiesProvider
import com.linagora.tmail.james.jmap.JMAPExtensionConfiguration.TICKET_IP_VALIDATION_ENABLED
import com.linagora.tmail.james.jmap.{JMAPExtensionConfiguration, TicketIpValidationEnable}
import org.apache.james.core.Username
import org.apache.james.utils.UpdatableTickingClock
import org.assertj.core.api.Assertions.{assertThat, assertThatThrownBy}
Expand All @@ -15,16 +15,14 @@ class TicketManagerTest {
private val username = Username.of("bob")
private val address = InetAddress.getByName("127.0.0.1")
var clock: UpdatableTickingClock = null
var propertiesProvider: FakePropertiesProvider = null
var jmapExtensionConfig: JMAPExtensionConfiguration = null
var testee: TicketManager = null

@BeforeEach
def setUp(): Unit = {
clock = new UpdatableTickingClock(initialDate.toInstant)
propertiesProvider = FakePropertiesProvider.builder()
.register("jmap", new PropertiesConfiguration)
.build()
testee = new TicketManager(clock, new MemoryTicketStore(), propertiesProvider)
jmapExtensionConfig = JMAPExtensionConfiguration()
testee = new TicketManager(clock, new MemoryTicketStore(), jmapExtensionConfig)
}

@Test
Expand All @@ -37,12 +35,8 @@ class TicketManagerTest {

@Test
def ticketShouldBeScopedBySourceIpWhenIpValidationEnabledExplicitly(): Unit = {
val jmapConfiguration: PropertiesConfiguration = new PropertiesConfiguration
jmapConfiguration.addProperty("authentication.strategy.rfc8621.tickets.ip.validation.enabled", "true")
propertiesProvider = FakePropertiesProvider.builder()
.register("jmap", jmapConfiguration)
.build()
testee = new TicketManager(clock, new MemoryTicketStore(), propertiesProvider)
jmapExtensionConfig = JMAPExtensionConfiguration(ticketIpValidationEnable = TICKET_IP_VALIDATION_ENABLED)
testee = new TicketManager(clock, new MemoryTicketStore(), jmapExtensionConfig)

val ticket = testee.generate(username, address).block()

Expand All @@ -52,12 +46,8 @@ class TicketManagerTest {

@Test
def ticketShouldNotBeScopedBySourceIpWhenIpValidationDisabled(): Unit = {
val jmapConfiguration: PropertiesConfiguration = new PropertiesConfiguration
jmapConfiguration.addProperty("authentication.strategy.rfc8621.tickets.ip.validation.enabled", "false")
propertiesProvider = FakePropertiesProvider.builder()
.register("jmap", jmapConfiguration)
.build()
testee = new TicketManager(clock, new MemoryTicketStore(), propertiesProvider)
jmapExtensionConfig = JMAPExtensionConfiguration(ticketIpValidationEnable = TicketIpValidationEnable(false))
testee = new TicketManager(clock, new MemoryTicketStore(), jmapExtensionConfig)

val ticket = testee.generate(username, address).block()

Expand Down

0 comments on commit 9d1579d

Please sign in to comment.