Skip to content

Verify ownership of user using HttpContext for all service methods #20

@Recelis

Description

@Recelis

Add pattern to all service methods for security purposes.

public async Task<Answer?> UpdateAsync(int id, UpdateAnswerDto updateAnswerDto)
{
    var userId = int.Parse(_httpContextAccessor.HttpContext?.User.FindFirst("id")?.Value ?? "0");
    if (userId <= 0)
        throw new UnauthorizedAccessException("User not authenticated");

    Answer? answer = await _lifeTrackerContext.Answer
        .Include(a => a.Submission)
        .FirstOrDefaultAsync(a => a.Id == id);
    
    if (answer == null)
    {
        _logger.LogError("Could not find answer of id {answer}", id);
        return null;
    }

    // Verify user owns the submission
    if (answer.Submission?.UserId != userId)
        throw new UnauthorizedAccessException("User does not own this submission");

    answer.Text = updateAnswerDto.Text;
    answer.Points = updateAnswerDto.Points;
    await _lifeTrackerContext.SaveChangesAsync();
    return answer;
}

With test pattern:

private static Mock<Microsoft.AspNetCore.Http.IHttpContextAccessor> CreateMockHttpContextAccessor(int userId)
        {
            var mockHttpContextAccessor = new Mock<Microsoft.AspNetCore.Http.IHttpContextAccessor>();
            var mockHttpContext = new Mock<Microsoft.AspNetCore.Http.HttpContext>();
            var mockUser = new Mock<System.Security.Claims.ClaimsPrincipal>();
            mockUser.Setup(u => u.FindFirst("id")).Returns(new System.Security.Claims.Claim("id", userId.ToString()));
            mockHttpContext.Setup(c => c.User).Returns(mockUser.Object);
            mockHttpContextAccessor.Setup(a => a.HttpContext).Returns(mockHttpContext.Object);
            return mockHttpContextAccessor;
        }

// Helper to initialize services with a specific user
private void InitializeServicesWithUser(User user)
{
var mockAccessor = CreateMockHttpContextAccessor(user.Id).Object;
_questionnaireService = new EFQuestionnaireService(_context, _questionnaireLogger, mockAccessor);
_submissionService = new EFSubmissionService(_context, _submissionLogger, mockAccessor);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions