org.surfnet.oaaas.resource.ResourceServerResource.java Source code

Java tutorial

Introduction

Here is the source code for org.surfnet.oaaas.resource.ResourceServerResource.java

Source

/*
 * Copyright 2012 SURFnet bv, The Netherlands
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.surfnet.oaaas.resource;

import static org.apache.commons.collections.CollectionUtils.subtract;

import java.net.URI;
import java.util.*;

import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.surfnet.oaaas.model.*;
import org.surfnet.oaaas.model.StatisticsResponse.ClientStat;
import org.surfnet.oaaas.model.StatisticsResponse.ResourceServerStat;
import org.surfnet.oaaas.repository.AccessTokenRepository;
import org.surfnet.oaaas.repository.ClientRepository;
import org.surfnet.oaaas.repository.ResourceServerRepository;

/**
 * JAX-RS Resource for resource servers.
 */
@Named
@Path("/resourceServer")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public class ResourceServerResource extends AbstractResource {

    private static final Logger LOG = LoggerFactory.getLogger(ResourceServerResource.class);

    @Inject
    private ResourceServerRepository resourceServerRepository;

    @Inject
    private AccessTokenRepository accessTokenRepository;

    @Inject
    private ClientRepository clientRepository;

    /**
     * Get all existing resource servers for the provided credentials (== owner).
     */
    @GET
    public Response getAll(@Context HttpServletRequest request) {
        Response validateScopeResponse = validateScope(request,
                Collections.singletonList(AbstractResource.SCOPE_READ));
        if (validateScopeResponse != null) {
            return validateScopeResponse;
        }

        Response.ResponseBuilder responseBuilder;
        String owner = getUserId(request);
        final List<ResourceServer> resourceServers = resourceServerRepository.findByOwner(owner);

        LOG.debug("About to return all resource servers ({}) for owner {}", resourceServers.size(), owner);
        responseBuilder = Response.ok(resourceServers);

        return responseBuilder.build();
    }

    /**
     * Get one resource server.
     */
    @GET
    @Path("/{resourceServerId}")
    public Response getById(@Context HttpServletRequest request, @PathParam("resourceServerId") Long id) {
        Response validateScopeResponse = validateScope(request,
                Collections.singletonList(AbstractResource.SCOPE_READ));
        if (validateScopeResponse != null) {
            return validateScopeResponse;
        }

        String owner = getUserId(request);

        Response.ResponseBuilder responseBuilder;
        final ResourceServer resourceServer = resourceServerRepository.findByIdAndOwner(id, owner);

        if (resourceServer == null) {
            responseBuilder = Response.status(Response.Status.NOT_FOUND);
        } else {
            responseBuilder = Response.ok(resourceServer);
        }
        LOG.debug("About to return one resourceServer with id {}: {}", id, resourceServer);
        return responseBuilder.build();
    }

    /**
     * Get statistics
     */
    @GET
    @Path("stats")
    public Response stats() {
        Iterable<ResourceServer> resourceServers = this.resourceServerRepository.findAll();
        List<ResourceServerStat> resourceServerStats = new ArrayList<StatisticsResponse.ResourceServerStat>();
        for (ResourceServer resourceServer : resourceServers) {
            List<ClientStat> clientStats = new ArrayList<StatisticsResponse.ClientStat>();
            Set<Client> clients = resourceServer.getClients();
            for (Client client : clients) {
                clientStats.add(new StatisticsResponse.ClientStat(client.getName(), client.getDescription(),
                        accessTokenRepository.countByUniqueResourceOwnerIdAndClientId(client.getId())));
            }
            resourceServerStats.add(new StatisticsResponse.ResourceServerStat(resourceServer.getName(),
                    resourceServer.getDescription(), clientStats));
        }
        return Response.ok(new StatisticsResponse(resourceServerStats)).build();
    }

    /**
     * Save a new resource server.
     */
    @PUT
    public Response put(@Context HttpServletRequest request, @Valid ResourceServer newOne) {
        Response validateScopeResponse = validateScope(request,
                Collections.singletonList(AbstractResource.SCOPE_WRITE));
        if (validateScopeResponse != null) {
            return validateScopeResponse;
        }

        String owner = getUserId(request);

        // Read only fields
        newOne.setKey(generateKey());
        newOne.setSecret(generateSecret());
        newOne.setOwner(owner);

        ResourceServer resourceServerSaved;
        try {
            resourceServerSaved = resourceServerRepository.save(newOne);
        } catch (Exception e) {
            return buildErrorResponse(e);
        }

        LOG.debug("New resourceServer has been saved: {}. ", resourceServerSaved);

        final URI uri = UriBuilder.fromPath("{resourceServerId}.json").build(resourceServerSaved.getId());
        return Response.created(uri).entity(resourceServerSaved).build();
    }

    /**
     * Delete an existing resource server.
     */
    @DELETE
    @Path("/{resourceServerId}")
    public Response delete(@Context HttpServletRequest request, @PathParam("resourceServerId") Long id) {
        Response validateScopeResponse = validateScope(request,
                Collections.singletonList(AbstractResource.SCOPE_WRITE));
        if (validateScopeResponse != null) {
            return validateScopeResponse;
        }

        String owner = getUserId(request);

        if (resourceServerRepository.findByIdAndOwner(id, owner) == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        LOG.debug("About to delete resourceServer {}", id);
        resourceServerRepository.delete(id);
        return Response.noContent().build();
    }

    /**
     * Update an existing resource server.
     */
    @POST
    @Path("/{resourceServerId}")
    public Response post(@Valid final ResourceServer resourceServer, @Context HttpServletRequest request,
            @PathParam("resourceServerId") Long id) {
        Response validateScopeResponse = validateScope(request,
                Collections.singletonList(AbstractResource.SCOPE_WRITE));
        if (validateScopeResponse != null) {
            return validateScopeResponse;
        }

        String owner = getUserId(request);

        ResourceServer persistedResourceServer = resourceServerRepository.findByIdAndOwner(id, owner);
        if (persistedResourceServer == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        // Copy over read-only fields
        resourceServer.setSecret(persistedResourceServer.getSecret());
        resourceServer.setKey(persistedResourceServer.getKey());
        resourceServer.setOwner(owner);

        pruneClientScopes(resourceServer.getScopes(), persistedResourceServer.getScopes(),
                persistedResourceServer.getClients());
        LOG.debug("About to update existing resourceServer {} with new properties: {}", persistedResourceServer,
                resourceServer);
        ResourceServer savedInstance = resourceServerRepository.save(resourceServer);
        return Response.ok(savedInstance).build();
    }

    /**
     * Delete all scopes from clients that are not valid anymore with the new
     * resource server
     *
     * @param newScopes
     *          the newly saved scopes
     * @param oldScopes
     *          the scopes from the existing resource server
     * @param clients
     *          the clients of the resource server
     */
    @SuppressWarnings("unchecked")
    protected void pruneClientScopes(final List<String> newScopes, List<String> oldScopes, Set<Client> clients) {
        if (!newScopes.containsAll(oldScopes)) {
            subtract(oldScopes, newScopes);
            Collection<String> outdatedScopes = subtract(oldScopes, newScopes);
            LOG.info("Resource server has updated scopes. Will remove all outdated scopes from clients: {}",
                    outdatedScopes);

            for (Client c : clients) {
                final List<String> clientScopes = c.getScopes();
                if (CollectionUtils.containsAny(clientScopes, outdatedScopes)) {
                    ArrayList<String> prunedScopes = new ArrayList<String>(subtract(clientScopes, outdatedScopes));
                    LOG.info(
                            "Client scopes of client {} were: {}. After pruning (because resourceServer has new scopes): {}",
                            new Object[] { c.getClientId(), c.getScopes(), prunedScopes });
                    c.setScopes(prunedScopes);
                }
            }
        }
    }

    protected String generateKey() {
        return super.generateRandom();
    }

    protected String generateSecret() {
        return super.generateRandom();
    }

}