theonedev/onedev · error · UnauthorizedException

Unauthorized

Error message

Unauthorized

What it means

BuildLogStreamResource.downloadLog streams a build's log and throws UnauthorizedException when SecurityUtils.canAccessLog(build) is false. Log access is a stricter privilege than general project access in OneDev, so users who can view a build may still be barred from reading its raw log. The check happens before any streaming begins.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/BuildLogStreamResource.java:65

	private final SessionService sessionService;
	
	@Inject
	public BuildLogStreamResource(BuildService buildService, LogService logService,
                                  ObjectMapper objectMapper, SessionService sessionService) {
		this.buildService = buildService;
		this.logService = logService;
		this.objectMapper = objectMapper;
		this.sessionService = sessionService;
	}
	
	@Api(order=200, description = "Streaming log of specified build")
	@Path("/{buildId}")
	@GET
	@Produces(APPLICATION_OCTET_STREAM)
	public StreamingOutput downloadLog(@PathParam("buildId") Long buildId) {
		Build build = buildService.load(buildId);
		if (!SecurityUtils.canAccessLog(build))
			throw new UnauthorizedException();
		
		var loggingSupport = build.getLoggingSupport();
		var buildStatus = build.getStatus();

		return os -> {
			writeStatus(os, buildStatus);
			var logListener = new LogListener() {

				@Override
				public void logged(LoggingSupport loggingSupport) {
					if (loggingSupport instanceof BuildLoggingSupport buildLoggingSupport 
							&& buildLoggingSupport.getBuildId().equals(buildId)) {
						synchronized (os) {
							os.notify();
						}
					}
				}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the user's role the 'Access Build Log' (or equivalent) permission on the project.
  2. Check the job/build configuration — some jobs restrict log visibility; relax it if appropriate.
  3. Use a token from an account that passes canAccessLog (project admin usually qualifies).
  4. Verify the request includes valid Authorization credentials; anonymous users are typically denied.

Example fix

// before
InputStream in = client.path("/rest/builds/" + buildId + "/log").get(InputStream.class);
// after: pick an identity allowed to read logs
// e.g. switch to an admin token or grant the role 'Access build logs' in project security settings
InputStream in = adminClient.path("/rest/builds/" + buildId + "/log").get(InputStream.class);
Defensive patterns

Strategy: validation

Validate before calling

// probe access with a cheap read before streaming
Response probe = client.path("/rest/builds/" + buildId).get();
if (probe.getStatus() != 200) throw new SecurityException("No access to build " + buildId + " log");

Try / catch

try (InputStream in = client.path("/rest/builds/" + id + "/log").get(InputStream.class)) {
    // consume
} catch (ProcessingException e) {
    if (e.getCause() instanceof IOException && String.valueOf(e).contains("401")) {
        throw new SecurityException("Log access denied — need 'Access build log' permission");
    }
    throw e;
}

Prevention

When it happens

Trigger: GET /rest/builds/{buildId}/log (octet-stream) as a user lacking log-access permission on the build's project — e.g. guest-level access, a token without log viewing rights, or jobs flagged to restrict log visibility.

Common situations: Downloading CI logs via API token with read-only role; projects that hide logs of security-sensitive jobs from non-admins; anonymous access attempts; monitoring scripts hitting the endpoint with an expired token.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/0572711555139dce. Report an issue: GitHub.