Есть ли способ получить список всех URL-адресов Джерси, на основе их роли и доступа @RolesAllowed? - PullRequest
0 голосов
/ 27 апреля 2019

Я надеюсь предложить клиентам остальные api-вызовы (через обычный джерси, а не пружину), чтобы вернуть список всех конечных точек, разрешенных для конкретного пользователя, на основе JWT, который они отправляют в заголовке. Я нашел пример кода stackoverflow (спасибо авторам!), Чтобы получить все конечные точки, независимо от роли, но не подмножество, основанное на роли. Я также нашел способ получения аннотаций для каждого метода, но хотел бы не изобретать колесо «if @PermitAll, а не @DenyAll, или роль в RolesAllowed и т. Д.».

Есть ли вероятность, что в Джерси 2.0 есть метод, который я могу вызвать, который разрешит значение true / false, учитывая SecurityContext и конечную точку или метод URL?

логическое разрешение = isMethodAllowed (SecurityContext ctx, строковый URL);

Или

логическое разрешение = isMethodAllowed (SecurityContext ctx, метод класса);

1 Ответ

0 голосов
/ 02 мая 2019

Благодаря этому сообщению: Перечисление всех развернутых конечных точек отдыха (spring-boot, jersey)

В частности, пост Иоганна Джандера (спасибо!), Я пришел к следующемукод, который, кажется, работает в моем случае, простой случай использования Джерси.Предоставляя его здесь на случай, если это будет полезно для других.

@Path("/v1/userinterface")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class MyUI extends MyRestApi {

    private final static Logger log = LoggerFactory.getLogger(MyUI.class);

    @Context
    private Configuration configuration;

    @Context
    private SecurityContext security;

    @Path("/allowedendpoints")
    @GET
    @Operation(summary = "List API access points allowed for the currently authenticated user", tags = {
        "ui" }, description = "Returns a list of urls", responses = {})
    public Response showAll(@Context UriInfo ui) {

    log.debug("Get list of all allowed endpoints for user: " + security.getUserPrincipal().getName());

    HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();

    for (Class<?> c : configuration.getClasses()) {
        // Since all of my endpoint classes extend MyRestApi,
        // only scan them, not all classes
        if (MyRestApi.class.isAssignableFrom(c)) {
        scanClass(c, map);
        }
    }

    return Response.ok().entity(map).build();
    }

    public void scanClass(Class<?> baseClass, HashMap<String, ArrayList<String>> map) {
    Builder builder = Resource.builder(baseClass);
    if (null != builder) {
        Resource resource = builder.build();
        String uriPrefix = "";
        process(uriPrefix, resource, map);
    }
    }

    private void process(String uriPrefix, Resource resource, HashMap<String, ArrayList<String>> map) {

    // recursive method

    String pathPrefix = uriPrefix;
    List<Resource> resources = new ArrayList<>();
    resources.addAll(resource.getChildResources());

    if (resource.getPath() != null) {
        pathPrefix = (pathPrefix + "/" + resource.getPath()).replaceAll("//", "/");
    }

    for (ResourceMethod method : resource.getAllMethods()) {
        if (method.getType().equals(ResourceMethod.JaxrsType.SUB_RESOURCE_LOCATOR)) {
        resources.add(Resource
            .from(resource.getResourceLocator().getInvocable().getDefinitionMethod().getReturnType()));
        } else {
        if (isPathAllowed(security, method.getInvocable().getDefinitionMethod())) {
            if (map.containsKey(pathPrefix))
            map.get(pathPrefix).add(method.getHttpMethod());
            else
            map.put(pathPrefix, new ArrayList<String>(Arrays.asList(method.getHttpMethod())));
        }
        }
    }

    for (Resource childResource : resources) {
        process(pathPrefix, childResource, map);
    }
    }

    public boolean isPathAllowed(SecurityContext ctx, Method method) {

    // @DenyAll on the method takes precedence over @RolesAllowed and @PermitAll
    if (method.isAnnotationPresent(DenyAll.class)) {
        return (false);
    }

    // @RolesAllowed on the method takes precedence over @PermitAll
    RolesAllowed rolesAllowed = method.getAnnotation(RolesAllowed.class);
    if (rolesAllowed != null) {
        return (hasRole(ctx, rolesAllowed.value()));
    }

    // @PermitAll on the method takes precedence over @RolesAllowed on the class
    if (method.isAnnotationPresent(PermitAll.class)) {
        return (true);
    }

    // @DenyAll can't be attached to classes

    // @RolesAllowed on the class takes precedence over @PermitAll on the class
    rolesAllowed = method.getDeclaringClass().getAnnotation(RolesAllowed.class);
    if (rolesAllowed != null) {
        return (hasRole(ctx, rolesAllowed.value()));
    }

    // @PermitAll on the class
    if (method.getDeclaringClass().isAnnotationPresent(PermitAll.class)) {
        return (true);
    }

    return (false); // default
    }

    private boolean hasRole(SecurityContext ctx, String[] rolesAllowed) {

    for (final String role : rolesAllowed) {
        if (ctx.isUserInRole(role)) {
        return (true);
        }
    }

    return (false);
    }

Возвращает конечные точки, к которым имеет доступ текущий аутентифицированный пользователь, на основе разметки SecurityContext с аннотациями @DenyAll, @PermitAll и @RolesAllowed.

Полное раскрытие, мое приложение просто с простыми аннотациями классов и методов на конечных точках.мммм.

Пример вывода:

{
   "/v1/resources" : [
      "POST",
      "GET"
   ],
   "/v1/resources/{id}" : [
      "DELETE",
      "GET"
   ]
}
...