Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/ApiService/ApiService/Functions/AgentRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ private async Async.Task<AgentRegistrationResponse> CreateRegistrationResponse(S
var baseAddress = _context.Creds.GetInstanceUrl();
var eventsUrl = new Uri(baseAddress, "/api/agents/events");
var commandsUrl = new Uri(baseAddress, "/api/agents/commands");

var workQueue = await _context.Queue.GetQueueSas(
_context.PoolOperations.GetPoolQueue(pool.PoolId),
StorageType.Corpus,
Expand Down
4 changes: 2 additions & 2 deletions src/ApiService/ApiService/Functions/Pool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private async Task<HttpResponseData> Post(HttpRequestData req) {
Errors: new string[] { "pool with that name already exists" }),
"PoolCreate");
}
var newPool = await _context.PoolOperations.Create(name: create.Name, os: create.Os, architecture: create.Arch, managed: create.Managed, clientId: create.ClientId);
var newPool = await _context.PoolOperations.Create(name: create.Name, os: create.Os, architecture: create.Arch, managed: create.Managed, objectId: create.ObjectId);
return await RequestHandling.Ok(req, await Populate(PoolToPoolResponse(newPool), true));
}

Expand Down Expand Up @@ -106,7 +106,7 @@ private static PoolGetResult PoolToPoolResponse(Service.Pool p)
PoolId: p.PoolId,
Os: p.Os,
State: p.State,
ClientId: p.ClientId,
ObjectId: p.ObjectId,
Managed: p.Managed,
Arch: p.Arch,
Nodes: p.Nodes,
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/OneFuzzTypes/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ public record Pool(
bool Managed,
Architecture Arch,
PoolState State,
Guid? ClientId = null
Guid? ObjectId = null
) : StatefulEntityBase<PoolState>(State) {
public List<Node>? Nodes { get; set; }
public AgentConfig? Config { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/OneFuzzTypes/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public record PoolCreate(
[property: Required] Os Os,
[property: Required] Architecture Arch,
[property: Required] bool Managed,
Guid? ClientId = null
Guid? ObjectId = null
) : BaseRequest;

public record WebhookCreate(
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/OneFuzzTypes/Responses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public record PoolGetResult(
bool Managed,
Architecture Arch,
PoolState State,
Guid? ClientId,
Guid? ObjectId,
List<Node>? Nodes,
AgentConfig? Config,
List<WorkSetSummary>? WorkQueue,
Expand Down
10 changes: 10 additions & 0 deletions src/ApiService/ApiService/ServiceConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public interface IServiceConfig {
// multiple instances to run against the same storage account, which
// is useful for things like integration testing.
public string OneFuzzStoragePrefix { get; }

public Uri OneFuzzBaseAddress { get; }
}

public class ServiceConfiguration : IServiceConfig {
Expand Down Expand Up @@ -134,4 +136,12 @@ public string OneFuzzVersion {

public string OneFuzzNodeDisposalStrategy { get => GetEnv("ONEFUZZ_NODE_DISPOSAL_STRATEGY") ?? "scale_in"; }
public string OneFuzzStoragePrefix => ""; // in production we never prefix the tables

public Uri OneFuzzBaseAddress {
get {
var hostName = Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME");
var scheme = Environment.GetEnvironmentVariable("HTTPS") != null ? "https" : "http";
return new Uri($"{scheme}://{hostName}");
}
}
}
40 changes: 21 additions & 19 deletions src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@ public virtual async Async.Task<HttpResponseData> CallIf(HttpRequestData req, Fu
}

var token = tokenResult.OkV.UserInfo;
if (await IsUser(tokenResult.OkV)) {

var (isAgent, reason) = await IsAgent(tokenResult.OkV);

if (!isAgent) {
if (!allowUser) {
return await Reject(req, token);
return await Reject(req, token, "endpoint not allowed for users");
}

var access = await CheckAccess(req);
Expand All @@ -57,26 +60,24 @@ public virtual async Async.Task<HttpResponseData> CallIf(HttpRequestData req, Fu
}
}

if (await IsAgent(tokenResult.OkV) && !allowAgent) {
return await Reject(req, token);

if (isAgent && !allowAgent) {
return await Reject(req, token, reason);
}

return await method(req);
}

public async Async.Task<bool> IsUser(UserAuthInfo tokenData) {
return !await IsAgent(tokenData);
}

public async Async.Task<HttpResponseData> Reject(HttpRequestData req, UserInfo token) {
public async Async.Task<HttpResponseData> Reject(HttpRequestData req, UserInfo token, String? reason = null) {
var body = await req.ReadAsStringAsync();
_log.Error($"reject token. url:{req.Url:Tag:Url} token:{token:Tag:Token} body:{body:Tag:Body}");
_log.Error($"reject token. reason:{reason} url:{req.Url:Tag:Url} token:{token:Tag:Token} body:{body:Tag:Body}");

return await _context.RequestHandling.NotOk(
req,
new Error(
ErrorCode.UNAUTHORIZED,
new string[] { "Unrecognized agent" }
new string[] { reason ?? "Unrecognized agent" }
),
"token verification",
HttpStatusCode.Unauthorized
Expand Down Expand Up @@ -186,34 +187,35 @@ private GroupMembershipChecker CreateGroupMembershipChecker(InstanceConfig confi
return null;
}

public async Async.Task<bool> IsAgent(UserAuthInfo authInfo) {

public async Async.Task<(bool, string)> IsAgent(UserAuthInfo authInfo) {
if (!AgentRoles.Overlaps(authInfo.Roles)) {
return false;
return (false, "no agent role");
}

var tokenData = authInfo.UserInfo;

if (tokenData.ObjectId != null) {
var scalesets = _context.ScalesetOperations.GetByObjectId(tokenData.ObjectId.Value);
if (await scalesets.AnyAsync()) {
return true;
return (true, string.Empty);
}

var principalId = await _context.Creds.GetScalesetPrincipalId();
if (principalId == tokenData.ObjectId) {
return true;
return (true, string.Empty);
}
}

if (!tokenData.ApplicationId.HasValue) {
return false;
if (!tokenData.ObjectId.HasValue) {
return (false, "no object id in token");
}

var pools = _context.PoolOperations.GetByClientId(tokenData.ApplicationId.Value);
var pools = _context.PoolOperations.GetByObjectId(tokenData.ObjectId.Value);
if (await pools.AnyAsync()) {
return true;
return (true, string.Empty);
}

return false;
return (false, "no matching scaleset or pool");
}
}
12 changes: 6 additions & 6 deletions src/ApiService/ApiService/onefuzzlib/PoolOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ public interface IPoolOperations : IStatefulOrm<Pool, PoolState> {
Async.Task<OneFuzzResult<Pool>> GetByName(PoolName poolName);
Async.Task<OneFuzzResult<Pool>> GetById(Guid poolId);
Task<bool> ScheduleWorkset(Pool pool, WorkSet workSet);
IAsyncEnumerable<Pool> GetByClientId(Guid clientId);
IAsyncEnumerable<Pool> GetByObjectId(Guid objectId);
string GetPoolQueue(Guid poolId);
Async.Task<List<ScalesetSummary>> GetScalesetSummary(PoolName name);
Async.Task<List<WorkSetSummary>> GetWorkQueue(Guid poolId, PoolState state);
IAsyncEnumerable<Pool> SearchStates(IEnumerable<PoolState> states);
Async.Task<Pool> SetShutdown(Pool pool, bool Now);

Async.Task<Pool> Create(PoolName name, Os os, Architecture architecture, bool managed, Guid? clientId = null);
Async.Task<Pool> Create(PoolName name, Os os, Architecture architecture, bool managed, Guid? objectId = null);
new Async.Task Delete(Pool pool);

// state transitions:
Expand All @@ -32,15 +32,15 @@ public PoolOperations(ILogTracer log, IOnefuzzContext context)

}

public async Async.Task<Pool> Create(PoolName name, Os os, Architecture architecture, bool managed, Guid? clientId = null) {
public async Async.Task<Pool> Create(PoolName name, Os os, Architecture architecture, bool managed, Guid? objectId = null) {
var newPool = new Service.Pool(
PoolId: Guid.NewGuid(),
State: PoolState.Init,
Name: name,
Os: os,
Managed: managed,
Arch: architecture,
ClientId: clientId);
ObjectId: objectId);

var r = await Insert(newPool);
if (!r.IsOk) {
Expand Down Expand Up @@ -87,8 +87,8 @@ public async Task<bool> ScheduleWorkset(Pool pool, WorkSet workSet) {
return await _context.Queue.QueueObject(GetPoolQueue(pool.PoolId), workSet, StorageType.Corpus);
}

public IAsyncEnumerable<Pool> GetByClientId(Guid clientId) {
return QueryAsync(filter: $"client_id eq '{clientId}'");
public IAsyncEnumerable<Pool> GetByObjectId(Guid objectId) {
return QueryAsync(filter: $"object_id eq '{objectId}'");
}

public string GetPoolQueue(Guid poolId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@ public TestServiceConfiguration(string tablePrefix) {

public string? OneFuzzAllowOutdatedAgent => throw new NotImplementedException();
public string? AppConfigurationEndpoint => throw new NotImplementedException();
public Uri OneFuzzBaseAddress { get => new Uri("http://test"); }
public string? AppConfigurationConnectionString => throw new NotImplementedException();
}
2 changes: 1 addition & 1 deletion src/agent/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
target
.agent-run
.agent-run
1 change: 1 addition & 0 deletions src/agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/agent/reqwest-retry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ backoff = { version = "0.4", features = ["tokio"] }
log = "0.4"
onefuzz-telemetry = { path = "../onefuzz-telemetry" }
reqwest = { version = "0.11", features = ["json", "stream", "native-tls-vendored"], default-features=false }
thiserror = "1.0"

[dev-dependencies]
tokio = { version = "1.16", features = ["macros"] }
Expand Down
Loading