2
\$\begingroup\$

I have a spring boot project with JWT being used for Spring Security. I want to implement Access Management in my project and I'm using this approach. In my project, whenever a user is created, a list of Departments is assigned to to the user. The user should be able to view and edit data that is related to the departments that have been assigned to them. I have implemented this using the below code, where the class Department is the Master data. A list of "assigned" Departments is associated with each User.

public class User implements UserDetails {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.UUID)
  private UUID id;

  private String username;

  private String password;

  @JsonManagedReference
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.EAGER)
  private List<AssignedDepartment> assignedDepartmentList = new ArrayList<>();

  public void setAssignedDepartment(List<AssignedDepartment> assignedDepartmentList1) {
    for(AssignedDepartment assignedDepartment : assignedDepartmentList1) {
      assignedDepartment.setUser(this);
      this.assignedDepartmentList.add(assignedDepartment);
    }
  }
}
public class AssignedDepartment {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "username", referencedColumnName = "username", nullable = false)
    private User user;

    @ManyToOne
    @JoinColumn(name = "department_code", referencedColumnName = "departmentCode")
    private Department department;
}
public class Department implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private String departmentCode;

    private String departmentName;
}

Considering the above implementation and approach and the below code, where I'm getting the list of assigned Departments from the JWT token (passed as a Bearer token) that is passed in the API request, is my implementation correct and safe? The below function is called every time any API is getting hit. I have tested the code and it works fine. The list of departments is always being fetched correctly based on the JWT token that I sent in the API request. I just want to confirm if there are any issues that might arise from this approach.

private List<String> getListOfDepartmentsAssignedToCurrentUser() throws Exception {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if(authentication == null || !authentication.isAuthenticated()) {
        throw new Exception("Unable to get departments for current user with authentication details: " + authentication);
    }

    try {
        List<AssignedDepartment> userAssignedDepartments = ((User) authentication.getPrincipal()).getUserAssignedDepartments();
        return userAssignedDepartments.stream()
                .map(m -> m.getDepartment().getDepartmentCode())
                .collect(Collectors.toList());
    } catch (Exception e) {
        throw new Exception("Error while streaming departments for current user with Exception: " + e.toString());
    }
}
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Storing that information in a token is a tradeoff from looking it up based on some other piece of information like a user ID. It saves you from having to look departments up for each API request at the cost of relying on a token's integrity and lifetime.

If a user's department list changes, that will only be reflected when a new token is issued and an old token will continue to be acceptable for as long as you have configured its lifetime. This may or may not be a security issue for you. Short lifetimes with refresh tokens are possible but validation relies on system clocks and token management packages usually have default jitter settings on the order of minutes, so you can have expiration validation issues when you get down to lifetimes of seconds or minutes. Revoking tokens is possible, but requires more infrastructure and a check each time a token is used.

Otherwise you want to make sure you choose an appropriate token signing algorithm consummate with your security needs.

\$\endgroup\$
5
  • \$\begingroup\$ Thank You for your response. So, the main possible issue that might arise is because of token lifetimes. Other than that, is my approach correct and feasible? \$\endgroup\$
    – Joe
    Commented Mar 21 at 11:55
  • \$\begingroup\$ I would say so given what you've presented and having ignorance on your security and infrastructure needs. I've seen similar systems in production. I take no responsibility and this is not professional advice. \$\endgroup\$
    – user223951
    Commented Mar 21 at 12:02
  • \$\begingroup\$ Do you have any suggestions on how to improve the above code in terms of security and performance, maybe? \$\endgroup\$
    – Joe
    Commented Mar 21 at 12:18
  • \$\begingroup\$ As is, I think it's fine if you can live with those token lifetimes I mentioned and you're signing it with something secure like RS256 (again, only you can say what is sufficient for security). I don't think you've got much to tweak with performance. \$\endgroup\$
    – user223951
    Commented Mar 21 at 12:22
  • \$\begingroup\$ Okay. Thank You for your answer! \$\endgroup\$
    – Joe
    Commented Mar 21 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.