Skip to content

Commit

Permalink
✨ Separation of voting session time and bearer token lifetime (#207) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Findeton authored Aug 8, 2024
1 parent 13fa1c2 commit 4039501
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 13 deletions.
3 changes: 2 additions & 1 deletion admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,8 @@ def get_hmac(cfg, userId, objType, objId, perm):

secret = settings["shared_secret"]
now = 1000*int(time.time())
message = "%s:%s:%d:%s:%d" % (userId, objType, objId, perm, now)
expiry = now+300
message = "%s:%s:%d:%s:%d:timeout-token:%d" % (userId, objType, objId, perm, expiry, now)
_hmac = hmac.new(str.encode(secret), str.encode(message), hashlib.sha256).hexdigest()
ret = 'khmac:///sha-256;%s/%s' % (_hmac, message)

Expand Down
3 changes: 2 additions & 1 deletion app/commands/Console.scala
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,8 @@ class ConsoleImpl extends ConsoleInterface {
case Some(time) => time
case None => System.currentTimeMillis / 1000
}
val message = s"$userId:$objType:$objId:$perm:$now"
val expiry: Long = now + 300
val message = s"$userId:$objType:$objId:$perm:$expiry:timeout-token:$now"
val hmac = Crypto.hmac(shared_secret, message)
val khmac = s"khmac:///sha-256;$hmac/$message"
khmac
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/BallotboxApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ object BallotboxApi extends Controller with Response {
val validated = vote.validate(pks, true, electionId, voterId)
val result = DAL.votes.insertWithSession(validated)
val now: Long = System.currentTimeMillis / 1000
val message = s"$voterId:AuthEvent:$electionId:RegisterSuccessfulLogin:$now"
val expiry: Long = now + 300
val message = s"$voterId:AuthEvent:$electionId:RegisterSuccessfulLogin:$expiry:timeout-token:$now"
voteCallbackUrl.map {
url => postVoteCallback(
url
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/ElectionsApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,8 @@ object ElectionsApi
println(s"posting to $url")
val userId: String = "admin"
val now: Long = System.currentTimeMillis / 1000
val timedAuth = s"$userId:AuthEvent:$electionId:Callback:$now"
val expiry: Long = now + 300
val timedAuth = s"$userId:AuthEvent:$electionId:Callback:$expiry:timeout-token:$now"
val hmac = Crypto.hmac(boothSecret, timedAuth)
val khmac = s"khmac:///sha-256;$hmac/$timedAuth"
val f = WS.url(url)
Expand Down
19 changes: 12 additions & 7 deletions app/utils/Actions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,17 @@ case class HMACActionHelper(
val message = authorizationHeader.substring(slashPos + 1)

val split = message.split(':')
if (split.length < 5) {
if (split.length < 7) {
Logger.warn(s"Malformed authorization header")
return Left(AuthErrorCodes.MALFORMED_USER_CREDENTIALS)
}

val rcvUserId = split.slice(0, split.length - 4).mkString(":")
val rcvObjType = split(split.length - 4)
val rcvObjId = split(split.length - 3).toLong
val rcvPerm = split(split.length - 2)
val rcvUserId = split.slice(0, split.length - 6).mkString(":")
val rcvObjType = split(split.length - 6)
val rcvObjId = split(split.length - 5).toLong
val rcvPerm = split(split.length - 4)
val rcvExpiryTime = split(split.length - 3).toLong
val rcvToken = split(split.length - 2)
val rcvTime = split(split.length - 1).toLong
val now = new java.util.Date().getTime / 1000
val diff = now - rcvTime
Expand All @@ -76,16 +78,19 @@ case class HMACActionHelper(
// if the userId is the empty string we don't mind the user
val userOk = (rcvUserId == userId || userId == "")

// Check if the current time is within the expiry timestamp
val withinExpiry = now <= rcvExpiryTime

// note that we can compare without doing contant time comparison received
// strings because that's not critical for security, only hmac is
if(compareOk && (diff < expiry) && userOk && (rcvObjType == objType) &&
if(compareOk && withinExpiry && userOk && (rcvObjType == objType) &&
(rcvObjId == objId) && permsOk)
{
return Right(true)
}

Logger.warn(
s"Failed to authorize hmac:\n\tauthorizationHeader=$authorizationHeader\tcompareOk=$compareOk\n\tdiff=$diff\n\texpiry=$expiry\n\tuserOk=$userOk\n\trcvObjType=$rcvObjType\n\tobjType=$objType\n\trcvObjId=$rcvObjId\n\tobjId=$objId\n\trcvPerm=$rcvPerm\n\tperm=$perm"
s"Failed to authorize hmac:\n\tauthorizationHeader=$authorizationHeader\tcompareOk=$compareOk\n\tdiff=$diff\n\texpiry=$expiry\n\tuserOk=$userOk\n\trcvObjType=$rcvObjType\n\tobjType=$objType\n\trcvObjId=$rcvObjId\n\tobjId=$objId\n\trcvPerm=$rcvPerm\n\tperm=$perm\n\tnow=$now\n\trcvExpiryTime=$rcvExpiryTime\n\t"
)
return Left(AuthErrorCodes.INVALID_USER_CREDENTIALS)
}
Expand Down
2 changes: 1 addition & 1 deletion test/ConsoleSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class ConsoleSpec extends Specification with TestContexts
val console = new ConsoleImpl()
console.shared_secret = "<PASSWORD>"
val khmac = console.get_khmac("user_id", "obj_type", 11, "perms", Some(22))
khmac must be equalTo(s"khmac:///sha-256;1ba07fd2e1becf9adfe74b4f6e0814fb4c9af3e0a920e718cec287857b480856/user_id:obj_type:11:perms:22")
khmac must be equalTo(s"khmac:///sha-256;1ba07fd2e1becf9adfe74b4f6e0814fb4c9af3e0a920e718cec287857b480856/user_id:obj_type:11:perms:322:timeout-token:22")
}
} // get_khmac

Expand Down
3 changes: 2 additions & 1 deletion test/TestUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ trait TestContexts {
def getAuth(userId: String, objType: String, objId: Long, perm: String) = {
val authSecret = Play.current.configuration.getString("elections.auth.secret").get
val time = (new java.util.Date().getTime / 1000)
val head = s"$userId:$objType:$objId:$perm:$time"
val expiry = time + 300
val head = s"$userId:$objType:$objId:$perm:$expiry:timeout-token:$time"

"khmac:///sha-256;" + Crypto.hmac(authSecret, head) + "/" + head
}
Expand Down

0 comments on commit 4039501

Please sign in to comment.