app/logic/UserAccess.scala (123 lines of code) (raw):
package logic
import com.gu.googleauth.UserIdentity
import com.gu.janus.model.{ACL, AwsAccount, Permission, SupportACL}
import java.time.{Duration, Instant}
object UserAccess {
/** Extract the username from the pan-domain user.
*/
def username(user: UserIdentity): String =
user.email.split("@").head.toLowerCase
/** A user's basic access. Note that default permissions are available for
* anyone mentioned in the Access list.
*/
def userAccess(username: String, acl: ACL): Option[Set[Permission]] = {
acl.userAccess
.get(username)
.map(permissions => permissions ++ acl.defaultPermissions)
}
/** Checks if the username is explicitly mentioned in the provided ACL.
*/
def hasAccess(username: String, acl: ACL): Boolean = {
acl.userAccess.keySet.contains(username)
}
// support access
def userSupportAccess(
username: String,
date: Instant,
supportACL: SupportACL
): Option[Set[Permission]] = {
if (isSupportUser(username, date, supportACL))
Some(supportACL.supportAccess)
else None
}
def isSupportUser(
username: String,
date: Instant,
supportACL: SupportACL
): Boolean = {
activeSupportUsers(date, supportACL).exists {
case (_, (maybeUser1, maybeUser2)) =>
maybeUser1.contains(username) || maybeUser2.contains(username)
}
}
/** Returns the usernames of the current support personnel, converting empty
* (TBD) users to None.
*/
def activeSupportUsers(
date: Instant,
supportACL: SupportACL
): Option[(Instant, (Option[String], Option[String]))] = {
supportACL.rota.find { case (startTime, _) =>
date.isAfter(startTime) && date.isBefore(
startTime.plus(supportACL.supportPeriod)
)
} map { case (startTime, (user1, user2)) =>
startTime -> (
if (user1.isEmpty) None else Some(user1),
if (user2.isEmpty) None else Some(user2)
)
}
}
def nextSupportUsers(
date: Instant,
supportACL: SupportACL
): Option[(Instant, (Option[String], Option[String]))] = {
activeSupportUsers(date.plus(Duration.ofDays(7)), supportACL)
}
/** Returns the start and end times of future (after active and next) slots
* for a given user
* @return
* Tuple of the start date and the other user on the rota
*/
def futureRotaSlotsForUser(
date: Instant,
supportACL: SupportACL,
user: String
): List[(Instant, String)] = {
supportACL.rota.toList
.sortBy(_._1.toEpochMilli)
.collect {
case (startTime, (user1, user2)) if user1 == user || user2 == user =>
(startTime, if (user1 == user) user2 else user1)
}
.filter { case (start, _) =>
start.isAfter(date.plus(supportACL.supportPeriod))
}
}
/** Combine a user's permissions from all sources to work out everything they
* can do.
*/
def allUserPermissions(
username: String,
date: Instant,
acl: ACL,
adminACL: ACL,
supportACL: SupportACL
): Set[Permission] = {
val access = userAccess(username, acl).getOrElse(Set.empty)
val adminAccess = userAccess(username, adminACL).getOrElse(Set.empty)
val supportAccess =
userSupportAccess(username, date, supportACL).getOrElse(Set.empty)
access ++ adminAccess ++ supportAccess
}
/** All the accounts this user has any access to.
*/
def allUserAccounts(
username: String,
date: Instant,
acl: ACL,
adminACL: ACL,
supportACL: SupportACL
): Set[AwsAccount] = {
allUserPermissions(username, date, acl, adminACL, supportACL).map(_.account)
}
/** Check if the provider user has been granted this permission.
*/
def checkUserPermission(
username: String,
permissionId: String,
date: Instant,
acl: ACL,
adminACL: ACL,
supportACL: SupportACL
): Option[Permission] = {
allUserPermissions(username, date, acl, adminACL, supportACL).find(
_.id == permissionId
)
}
/** Check if the user has explicit access granted in the Access.scala file.
*/
def hasExplicitAccess(
username: String,
permission: Permission,
acl: ACL
): Boolean = {
userAccess(username, acl).getOrElse(Set.empty).contains(permission)
}
/** Checks if a user has access to an account and returns appropriate
* permissions (if any).
*/
def userAccountAccess(
username: String,
accountId: String,
date: Instant,
acl: ACL,
adminACL: ACL,
supportACL: SupportACL
): Set[Permission] = {
allUserPermissions(username, date, acl, adminACL, supportACL)
.filter(_.account.authConfigKey == accountId)
}
}