Skip to content

Commit

Permalink
Change permission to unix style
Browse files Browse the repository at this point in the history
  • Loading branch information
ningyougang committed May 11, 2020
1 parent 38053a6 commit d77a80f
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ case class WhiskActionPut(exec: Option[Exec] = None,
limits: Option[ActionLimitsOption] = None,
version: Option[SemVer] = None,
publish: Option[Boolean] = None,
annotations: Option[Parameters] = None,
unlock: Option[Boolean] = None) {
annotations: Option[Parameters] = None) {

protected[core] def replace(exec: Exec) = {
WhiskActionPut(Some(exec), parameters, limits, version, publish, annotations)
Expand All @@ -76,6 +75,17 @@ case class WhiskActionPut(exec: Option[Exec] = None,
case _ => this
} getOrElse this
}

protected[core] def getPermissions(): String = {
annotations match {
case Some(value) =>
value
.get(WhiskAction.permissionsFieldName)
.map(value => value.convertTo[String])
.getOrElse(WhiskAction.defaultPermissions)
case None => WhiskAction.defaultPermissions
}
}
}

abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntity(name, "action") {
Expand Down Expand Up @@ -352,6 +362,24 @@ object WhiskAction extends DocumentFactory[WhiskAction] with WhiskEntityQueries[
val requireWhiskAuthHeader = "x-require-whisk-auth"
val lockFieldName = "lock"

// annotation permission key name
val permissionsFieldName = "permissions"

// action is used by two type user, one is its owner, the owner has read(yes)/write(yes)/execute(yes) permissions by default,
// another user uses the shared action who has read(yes)/write(no)/execute(yes) permissions permissions by default
// only the owner can modify the permissions
val defaultPermissions = "rwxr-x"

// includes below permission codes only for action.
// permission code:rwxr-x or 75: owner:read(yes)/write(yes)/execute(yes)|the shared action's user:read(yes)/write(no)/execute(yes), this is default
// permission code:r-xr-x or 55: owner:read(yes)/write(no)/execute(yes)|the shared action's user:read(yes)/write(no)/execute(yes)
// permission code:r--r-- or 44: owner:read(yes)/write(no)/execute(no)|the shared action's user:read(yes)/write(no)/execute(no)
// permission code:rx-r-- or 64: owner:read(yes)/write(yes)/execute(no)|the shared action's user:read(yes)/write(no)/execute(no)
// permission code:-wx--x or 31: owner:read(no)/write(yes)/execute(yes)|the shared action's user:read(no)/write(no)/execute(yes)
// permission code:--x--x or 11: owner:read(no)/write(no)/execute(yes)|the shared action's user:read(no)/write(no)/execute(yes)
// permission code:------ or 00: owner:read(no)/write(no)/execute(no)|the shared action's user:read(no)/write(no)/execute(no)
val permissionList = List(defaultPermissions, "r-xr-x", "r--r--", "rx-r--", "-wx--x", "--x--x", "------")

override val collectionName = "actions"
override val cacheEnabled = true

Expand Down Expand Up @@ -645,5 +673,5 @@ object ActionLimitsOption extends DefaultJsonProtocol {
}

object WhiskActionPut extends DefaultJsonProtocol {
implicit val serdes = jsonFormat7(WhiskActionPut.apply)
implicit val serdes = jsonFormat6(WhiskActionPut.apply)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,16 @@ package org.apache.openwhisk.http
import scala.concurrent.duration.Duration
import scala.concurrent.duration.FiniteDuration
import scala.util.Try

import akka.http.scaladsl.model.StatusCode
import akka.http.scaladsl.model.StatusCodes.Forbidden
import akka.http.scaladsl.model.StatusCodes.NotFound
import akka.http.scaladsl.model.MediaType
import akka.http.scaladsl.server.Directives
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport.sprayJsonMarshaller
import akka.http.scaladsl.server.StandardRoute

import spray.json._

import org.apache.openwhisk.common.TransactionId
import org.apache.openwhisk.core.entity.SizeError
import org.apache.openwhisk.core.entity.ByteSize
import org.apache.openwhisk.core.entity.Exec
import org.apache.openwhisk.core.entity.ExecMetaDataBase
import org.apache.openwhisk.core.entity.ActivationId
import org.apache.openwhisk.core.entity.{ActivationId, ByteSize, Exec, ExecMetaDataBase, SizeError, WhiskAction}

object Messages {

Expand Down Expand Up @@ -83,6 +76,8 @@ object Messages {
s"The supplied authentication is not authorized to access '$value'."
def notAuthorizedtoActionKind(value: String) =
s"The supplied authentication is not authorized to access actions of kind '$value'."
def notAuthorizedtoActionPermission(value: String) =
s"The supplied authentication is not authorized to give permission code: '$value', available permission is in ${WhiskAction.permissionList}"

/** Standard error message for malformed fully qualified entity names. */
val malformedFullyQualifiedEntityName =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,16 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
val checkAdditionalPrivileges = entitleReferencedEntities(user, Privilege.READ, request.exec).flatMap {
case _ => entitlementProvider.check(user, content.exec)
}
val unlock = content.unlock.getOrElse(false)

onComplete(checkAdditionalPrivileges) {
case Success(_) =>
putEntity(WhiskAction, entityStore, entityName.toDocId, overwrite, update(user, request) _, () => {
make(user, entityName, request)
}, unlock = unlock)
onComplete(entitlementProvider.checkActionPermissions(content.getPermissions())) {
case Success(_) =>
putEntity(WhiskAction, entityStore, entityName.toDocId, overwrite, update(user, request) _, () => {
make(user, entityName, request)
})
case Failure(f) => super.handleEntitlementFailure(f)
}
case Failure(f) =>
super.handleEntitlementFailure(f)
}
Expand Down Expand Up @@ -554,9 +557,7 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
content.version getOrElse action.version.upPatch,
content.publish getOrElse action.publish,
WhiskActionsApi
.amendAnnotations(content.annotations getOrElse action.annotations, exec, create = false) ++ content.unlock
.map(u => Parameters(WhiskAction.lockFieldName, JsBoolean(!u)))
.getOrElse(Parameters()))
.amendAnnotations(content.annotations getOrElse action.annotations, exec, create = false))
.revision[WhiskAction](action.docinfo.rev)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,18 @@ import scala.util.Failure
import scala.util.Success
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.StatusCode
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.model.StatusCodes.Conflict
import akka.http.scaladsl.model.StatusCodes.InternalServerError
import akka.http.scaladsl.model.StatusCodes.NotFound
import akka.http.scaladsl.model.StatusCodes.OK
import akka.http.scaladsl.server.{Directives, RequestContext, RouteResult}
import spray.json.DefaultJsonProtocol._
import spray.json.{JsObject, JsValue, RootJsonFormat}
import org.apache.openwhisk.common.Logging
import org.apache.openwhisk.common.TransactionId
import org.apache.openwhisk.core.controller.PostProcess.PostProcessEntity
import org.apache.openwhisk.core.database._
import org.apache.openwhisk.core.entity.{
ActivationId,
ActivationLogs,
DocId,
WhiskAction,
WhiskActivation,
WhiskDocument
}
import org.apache.openwhisk.core.entity.{ActivationId, ActivationLogs, DocId, WhiskActivation, WhiskDocument}
import org.apache.openwhisk.http.ErrorResponse
import org.apache.openwhisk.http.ErrorResponse.terminate
import org.apache.openwhisk.http.Messages._
Expand Down Expand Up @@ -314,8 +310,7 @@ trait WriteOps extends Directives {
update: A => Future[A],
create: () => Future[A],
treatExistsAsConflict: Boolean = true,
postProcess: Option[PostProcessEntity[A]] = None,
unlock: Boolean = false)(
postProcess: Option[PostProcessEntity[A]] = None)(
implicit transid: TransactionId,
format: RootJsonFormat[A],
notifier: Option[CacheChangeNotification],
Expand All @@ -340,24 +335,8 @@ trait WriteOps extends Directives {
} flatMap {
case (old, a) =>
logging.debug(this, s"[PUT] entity created/updated, writing back to datastore")
if (overwrite && !unlock && old.getOrElse(None).isInstanceOf[WhiskAction]) {
val oldWhiskAction = old.getOrElse(None).asInstanceOf[WhiskAction]
oldWhiskAction.annotations.get(WhiskAction.lockFieldName) match {
case Some(value) if (value.convertTo[Boolean]) => {
Future failed RejectRequest(
MethodNotAllowed,
s"this action can't be updated until ${WhiskAction.lockFieldName} annotation is updated to false")
}
case _ => {
factory.put(datastore, a, old) map { _ =>
a
}
}
}
} else {
factory.put(datastore, a, old) map { _ =>
a
}
factory.put(datastore, a, old) map { _ =>
a
}
}) {
case Success(entity) =>
Expand Down Expand Up @@ -411,30 +390,11 @@ trait WriteOps extends Directives {
notifier: Option[CacheChangeNotification],
ma: Manifest[A]) = {
onComplete(factory.get(datastore, docid) flatMap { entity =>
if (entity.isInstanceOf[WhiskAction]) {
val whiskAction = entity.asInstanceOf[WhiskAction]
whiskAction.annotations.get(WhiskAction.lockFieldName) match {
case Some(value) if (value.convertTo[Boolean]) => {
Future failed RejectRequest(
MethodNotAllowed,
s"this action can't be deleted until ${WhiskAction.lockFieldName} annotation is updated to false")
confirm(entity) flatMap {
case _ =>
factory.del(datastore, entity.docinfo) map { _ =>
entity
}
case _ => {
confirm(entity) flatMap {
case _ =>
factory.del(datastore, entity.docinfo) map { _ =>
entity
}
}
}
}
} else {
confirm(entity) flatMap {
case _ =>
factory.del(datastore, entity.docinfo) map { _ =>
entity
}
}
}
}) {
case Success(entity) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,21 @@ protected[core] abstract class EntitlementProvider(
.getOrElse(Future.successful(()))
}

/**
* Checks if an action permission code is whether right
*
* @param permissions the permission code
* @return a promise that completes with success iff the permission code is right
*/
protected[core] def checkActionPermissions(permissions: String)(implicit transid: TransactionId): Future[Unit] = {
if (WhiskAction.permissionList.contains(permissions)) {
Future.successful(())
} else {
Future.failed(
RejectRequest(Forbidden, Some(ErrorResponse(Messages.notAuthorizedtoActionPermission(permissions), transid))))
}
}

/**
* Checks if a subject has the right to access a specific resource. The entitlement may be implicit,
* that is, inferred based on namespaces that a subject belongs to and the namespace of the
Expand Down

0 comments on commit d77a80f

Please sign in to comment.