Skip to content

Commit a3b2a09

Browse files
committed
allow fine-grained access control in php
Signed-off-by: Robert Landers <landers.robert@gmail.com>
1 parent 9093267 commit a3b2a09

26 files changed

Lines changed: 267 additions & 59 deletions

cli/auth/resource.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func (r *Resource) getOrCreatePermissions(id *ids.StateId, ctx context.Context,
148148

149149
glu := glue.NewGlue(ctx.Value("bootstrap").(string), glue.GetPermissions, make([]any, 0), result.Name())
150150
env := map[string]string{"STATE_ID": id.String()}
151-
_, headers, _, _ := glu.Execute(ctx, make(http.Header), logger, env, nil, id)
151+
_, headers, _, _ := glu.Execute(ctx, make(http.Header), logger, env, nil, id, ids.SystemSource)
152152
data := headers.Get("Permissions")
153153
if err = json.Unmarshal([]byte(data), &perms); err != nil {
154154
return perms, err

cli/auth/resourceManager.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,19 @@ func (r *ResourceManager) ToAuthContext(ctx context.Context, resource *Resource)
120120
}
121121
}
122122

123+
fromIds := []string{}
124+
for _, f := range resource.AllowedFromIds {
125+
fromIds = append(fromIds, f.String())
126+
}
127+
123128
c := map[string]interface{}{
124129
"contextId": map[string]string{
125130
"id": resource.id.String(),
126131
},
127-
"owners": owners,
128-
"shares": shares,
132+
"owners": owners,
133+
"shares": shares,
134+
"fromTypes": resource.AllowedFromTypes,
135+
"fromIds": fromIds,
129136
}
130137

131138
return json.Marshal(c)

cli/glue/glue.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func NewGlue(bootstrap string, function Method, input []any, payload string) *Gl
7373
}
7474
}
7575

76-
func FromApiRequest(ctx context.Context, r *http.Request, function Method, logger *zap.Logger, stream jetstream.JetStream, id *ids.StateId, headers http.Header) ([]*nats.Msg, string, error, *http.Header, bool) {
76+
func FromApiRequest(ctx context.Context, r *http.Request, function Method, logger *zap.Logger, stream jetstream.JetStream, id *ids.StateId, from *ids.StateId, headers http.Header) ([]*nats.Msg, string, error, *http.Header, bool) {
7777
temp, err := os.CreateTemp("", "reqbody")
7878
if err != nil {
7979
return nil, "", err, nil, false
@@ -103,7 +103,7 @@ func FromApiRequest(ctx context.Context, r *http.Request, function Method, logge
103103
remoteAddr := strings.Split(r.RemoteAddr, ":")[0]
104104
env["REMOTE_ADDR"] = remoteAddr
105105

106-
msgs, responseHeaders, _, deleteAfter := glu.Execute(ctx, headers, logger, env, stream, id)
106+
msgs, responseHeaders, _, deleteAfter := glu.Execute(ctx, headers, logger, env, stream, id, from)
107107

108108
for _, msg := range msgs {
109109
msg.Header.Add("Remote-Addr", remoteAddr)
@@ -112,7 +112,7 @@ func FromApiRequest(ctx context.Context, r *http.Request, function Method, logge
112112
return msgs, temp.Name(), nil, &responseHeaders, deleteAfter
113113
}
114114

115-
func (g *Glue) Execute(ctx context.Context, headers http.Header, logger *zap.Logger, env map[string]string, stream jetstream.JetStream, id *ids.StateId) ([]*nats.Msg, http.Header, int, bool) {
115+
func (g *Glue) Execute(ctx context.Context, headers http.Header, logger *zap.Logger, env map[string]string, stream jetstream.JetStream, id *ids.StateId, from *ids.StateId) ([]*nats.Msg, http.Header, int, bool) {
116116
var dir string
117117
var ok bool
118118
if dir, ok = GetLibraryDir("glue.php"); !ok {
@@ -126,6 +126,7 @@ func (g *Glue) Execute(ctx context.Context, headers http.Header, logger *zap.Log
126126
headers.Add("DPHP_BOOTSTRAP", g.bootstrap)
127127
headers.Add("DPHP_FUNCTION", string(g.function))
128128
headers.Add("DPHP_PAYLOAD", g.payload)
129+
headers.Add("DPHP_SOURCE", from.String())
129130

130131
provenance := ctx.Value(appcontext.CurrentUserKey)
131132
if provenance != nil {

cli/ids/id.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ var ApiSource *StateId = &StateId{
1919
Kind: "--api--",
2020
}
2121

22+
var SystemSource *StateId = &StateId{
23+
Id: "--system--",
24+
Kind: "--system--",
25+
}
26+
2227
// subjects
2328

2429
type Subject struct {

cli/lib/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
272272
headers.Add("DPHP_AUTH_CONTEXT", string(ac))
273273
}
274274

275-
msgs, stateFile, err, responseHeaders, deleteAfter := glue.FromApiRequest(ctx, request, function, logger, js, id, headers)
275+
msgs, stateFile, err, responseHeaders, deleteAfter := glue.FromApiRequest(ctx, request, function, logger, js, id, ids.ApiSource, headers)
276276
if err != nil {
277277
http.Error(writer, "Internal Server Error", http.StatusInternalServerError)
278278
logger.Error("Failed to glue", zap.Error(err))

cli/lib/consumer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ func processMsg(ctx context.Context, logger *zap.Logger, msg jetstream.Msg, js j
336336
headers.Add("DPHP_AUTH_CONTEXT", string(ac))
337337
}
338338

339-
msgs, headers, _, deleteAfter := glu.Execute(ctx, headers, logger, env, js, id)
339+
msgs, headers, _, deleteAfter := glu.Execute(ctx, headers, logger, env, js, id, sourceId)
340340

341341
// now update the stored state, if this fails due to optimistic concurrency, we immediately nak and fail
342342
err = update()

src/Contexts/AuthContext.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
#[SequenceField(arrayType: Share::class)]
2626
public array $shares;
2727

28+
#[SequenceField(arrayType: 'string')]
29+
public array $fromTypes;
30+
31+
#[SequenceField(arrayType: StateId::class)]
32+
public array $fromIds;
33+
2834
public static function fromCurrentContext(): ?AuthContext
2935
{
3036
if (isset($_SERVER['HTTP_DPHP_AUTH_CONTEXT'])) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace Bottledcode\DurablePhp\Contexts\AuthContext;
4+
5+
class SecurityException extends \RuntimeException {}

src/Contexts/AuthContext/functions.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Bottledcode\DurablePhp\Contexts\AuthContext\Share\Role;
77
use Bottledcode\DurablePhp\Contexts\AuthContext\Share\User;
88
use Bottledcode\DurablePhp\Events\Shares\Operation;
9+
use Bottledcode\DurablePhp\State\Ids\StateId;
910
use ReflectionClass;
1011

1112
function Owner(string $subject): Owner
@@ -28,3 +29,6 @@ function User(string $subject, Operation ...$allowed): User
2829

2930
return $ref->getMethod('fromArgs')->invoke(null, subject: $subject, allowed: $allowed);
3031
}
32+
33+
define('ApiSource', StateId::fromString('--api--:--api--'));
34+
define('SystemSource', StateId::fromString('--system--:--system--'));

src/Glue/glue.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ class Glue
7070

7171
public StateId $target;
7272

73+
public StateId $source;
74+
7375
public $payloadHandle;
7476

7577
public array $payload = [];
@@ -102,6 +104,7 @@ public function __construct(private DurableLogger $logger)
102104
);
103105
$this->provenance = null;
104106
}
107+
$this->source = StateId::fromString($_SERVER['HTTP_DPHP_SOURCE']);
105108

106109
if (! file_exists($_SERVER['HTTP_DPHP_PAYLOAD'])) {
107110
throw new LogicException('Unable to load payload');

0 commit comments

Comments
 (0)