/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.usergrid.rest.management.organizations; import com.fasterxml.jackson.jaxrs.json.annotation.JSONP; import org.apache.amber.oauth2.common.exception.OAuthSystemException; import org.apache.commons.lang.NullArgumentException; import org.apache.usergrid.exception.NotImplementedException; import org.apache.usergrid.management.ActivationState; import org.apache.usergrid.management.OrganizationConfig; import org.apache.usergrid.management.OrganizationInfo; import org.apache.usergrid.management.export.ExportService; import org.apache.usergrid.persistence.entities.Export; import org.apache.usergrid.rest.AbstractContextResource; import org.apache.usergrid.rest.ApiResponse; import org.apache.usergrid.rest.applications.ServiceResource; import org.apache.usergrid.rest.exceptions.RedirectionException; import org.apache.usergrid.rest.management.organizations.applications.ApplicationsResource; import org.apache.usergrid.rest.management.organizations.users.UsersResource; import org.apache.usergrid.rest.security.annotations.RequireOrganizationAccess; import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; import org.apache.usergrid.rest.utils.JSONPUtils; import org.apache.usergrid.security.oauth.ClientCredentialsInfo; import org.apache.usergrid.security.tokens.exceptions.TokenException; import org.apache.usergrid.services.ServiceResults; import org.glassfish.jersey.server.mvc.Viewable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; 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.UriInfo; import java.util.*; import static javax.servlet.http.HttpServletResponse.*; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; @Component("org.apache.usergrid.rest.management.organizations.OrganizationResource") @Scope("prototype") @Produces({ MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", "application/ecmascript", "text/jscript" }) public class OrganizationResource extends AbstractContextResource { private static final Logger logger = LoggerFactory.getLogger( OrganizationsResource.class ); //@Autowired //protected ExportService exportService; OrganizationInfo organization; public OrganizationResource() { if (logger.isTraceEnabled()) { logger.trace("OrganizationResource created"); } } public OrganizationResource init( OrganizationInfo organization ) { this.organization = organization; if (logger.isTraceEnabled()) { logger.trace("OrganizationResource initialized for org {}", organization.getName()); } return this; } @Path("users") public UsersResource getOrganizationUsers( @Context UriInfo ui ) throws Exception { return getSubResource( UsersResource.class ).init( organization ); } @Path("applications") public ApplicationsResource getOrganizationApplications( @Context UriInfo ui ) throws Exception { return getSubResource( ApplicationsResource.class ).init( organization ); } @Path("apps") public ApplicationsResource getOrganizationApplications2( @Context UriInfo ui ) throws Exception { return getSubResource( ApplicationsResource.class ).init( organization ); } @GET @JSONP @RequireOrganizationAccess @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse getOrganizationDetails( @Context UriInfo ui, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Get details for organization: {}", organization.getUuid()); } ApiResponse response = createApiResponse(); response.setProperty( "organization", management.getOrganizationData( organization ) ); return response; } @GET @Path("activate") @Produces(MediaType.TEXT_HTML) public Viewable activate( @Context UriInfo ui, @QueryParam("token") String token ) { try { management.handleActivationTokenForOrganization( organization.getUuid(), token ); return handleViewable( "activate", this, organization.getName() ); } catch ( TokenException e ) { return handleViewable( "bad_activation_token", this, organization.getName() ); } catch ( RedirectionException e ) { throw e; } catch ( Exception e ) { return handleViewable( "error", e, organization.getName() ); } } @GET @Path("confirm") @Produces(MediaType.TEXT_HTML) public Viewable confirm( @Context UriInfo ui, @QueryParam("token") String token ) { try { ActivationState state = management.handleActivationTokenForOrganization( organization.getUuid(), token ); if ( state == ActivationState.CONFIRMED_AWAITING_ACTIVATION ) { return handleViewable( "confirm", this, organization.getName() ); } return handleViewable( "activate", this, organization.getName() ); } catch ( TokenException e ) { return handleViewable( "bad_activation_token", this, organization.getName() ); } catch ( RedirectionException e ) { throw e; } catch ( Exception e ) { return handleViewable( "error", e, organization.getName() ); } } @GET @Path("reactivate") @JSONP @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse reactivate( @Context UriInfo ui, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { logger.info("Send activation email for organization: {}", organization.getUuid()); ApiResponse response = createApiResponse(); management.startOrganizationActivationFlow( organization ); response.setAction( "reactivate organization" ); return response; } @RequireOrganizationAccess @GET @Path("feed") @JSONP @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse getFeed( @Context UriInfo ui, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { ApiResponse response = createApiResponse(); response.setAction( "get organization feed" ); ServiceResults results = management.getOrganizationActivity( organization ); response.setEntities( results.getEntities() ); response.setSuccess(); return response; } @RequireOrganizationAccess @GET @Path("credentials") @JSONP @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse getCredentials( @Context UriInfo ui, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { ApiResponse response = createApiResponse(); response.setAction( "get organization client credentials" ); ClientCredentialsInfo keys = new ClientCredentialsInfo( management.getClientIdForOrganization( organization.getUuid() ), management.getClientSecretForOrganization( organization.getUuid() ) ); response.setCredentials( keys ); return response; } @RequireOrganizationAccess @POST @Path("credentials") @JSONP @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse generateCredentials( @Context UriInfo ui, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { ApiResponse response = createApiResponse(); response.setAction( "generate organization client credentials" ); ClientCredentialsInfo credentials = new ClientCredentialsInfo( management.getClientIdForOrganization( organization.getUuid() ), management.newClientSecretForOrganization( organization.getUuid() ) ); response.setCredentials( credentials ); return response; } public OrganizationInfo getOrganization() { return organization; } @RequireOrganizationAccess @Consumes(MediaType.APPLICATION_JSON) @PUT @JSONP @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ApiResponse executePut( @Context UriInfo ui, Map<String, Object> json, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { if (logger.isTraceEnabled()) { logger.trace("executePut"); } ApiResponse response = createApiResponse(); response.setAction( "put" ); response.setParams( ui.getQueryParameters() ); Map customProperties = ( Map ) json.get( OrganizationsResource.ORGANIZATION_PROPERTIES ); organization.setProperties( customProperties ); management.updateOrganization( organization ); return response; } // @POST // @Path("export") // @Consumes(APPLICATION_JSON) // @RequireOrganizationAccess // public Response exportPostJson( @Context UriInfo ui,Map<String, Object> json, // @QueryParam("callback") @DefaultValue("") String callback ) // throws OAuthSystemException { // // if (logger.isTraceEnabled()) { // logger.trace("executePostJson"); // } // // Map<String, String> uuidRet = new HashMap<>(); // // try { // Object propertiesObj = json.get("properties"); // if (propertiesObj == null) { // throw new NullArgumentException("Could not find 'properties'"); // } // if (!(propertiesObj instanceof Map)) { // throw new IllegalArgumentException("'properties' not a map"); // } // // @SuppressWarnings("unchecked") // Map<String,Object> properties = (Map<String,Object>)propertiesObj; // // String storage_provider = ( String ) properties.get( "storage_provider" ); // if(storage_provider == null) { // throw new NullArgumentException( "Could not find field 'storage_provider'" ); // } // // Object storageInfoObj = properties.get("storage_info"); // if(storageInfoObj == null) { // throw new NullArgumentException( "Could not find field 'storage_info'" ); // } // @SuppressWarnings("unchecked") // Map<String,Object> storage_info = (Map<String, Object>)storageInfoObj; // // String bucketName = ( String ) storage_info.get( "bucket_location" ); // String accessId = ( String ) storage_info.get( "s3_access_id" ); // String secretKey = ( String ) storage_info.get( "s3_key" ); // // if ( bucketName == null ) { // throw new NullArgumentException( "Could not find field 'bucketName'" ); // } // if ( accessId == null ) { // throw new NullArgumentException( "Could not find field 's3_access_id'" ); // } // if ( secretKey == null ) { // // throw new NullArgumentException( "Could not find field 's3_key'" ); // } // // json.put( "organizationId",organization.getUuid()); // // UUID jobUUID = exportService.schedule( json ); // uuidRet.put( "Export Entity", jobUUID.toString() ); // } // catch ( NullArgumentException e ) { // return Response.status( SC_BAD_REQUEST ).type( JSONPUtils.jsonMediaType( callback ) ) // .entity( ServiceResource.wrapWithCallback( e.getMessage(), callback ) ).build(); // } // catch ( Exception e ) { // //TODO:throw descriptive error message and or include on in the response // //TODO:fix below, it doesn't work if there is an exception. Make it look like the OauthResponse. // return Response.status( SC_INTERNAL_SERVER_ERROR ).type( JSONPUtils.jsonMediaType( callback ) ) // .entity( ServiceResource.wrapWithCallback( e.getMessage(), callback ) ).build(); // } // return Response.status( SC_ACCEPTED ).entity( uuidRet ).build(); // } // @GET // @RequireOrganizationAccess // @Path("export/{exportEntity: [A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}}") // public Response exportGetJson( @Context UriInfo ui, @PathParam("exportEntity") UUID exportEntityUUIDStr, // @QueryParam("callback") @DefaultValue("") String callback ) throws Exception { // // Export entity; // try { // entity = smf.getServiceManager( emf.getManagementAppId() ).getEntityManager() // .get( exportEntityUUIDStr, Export.class ); // } // catch ( Exception e ) { //this might not be a bad request and needs better error checking // return Response.status( SC_BAD_REQUEST ).type( JSONPUtils.jsonMediaType( callback ) ) // .entity( ServiceResource.wrapWithCallback( e.getMessage(), callback ) ).build(); // } // // if ( entity == null ) { // return Response.status( SC_BAD_REQUEST ).build(); // } // // return Response.status( SC_OK ).entity( entity).build(); // } protected Set<String> getSetFromCommaSeparatedString(String input) { Set<String> ret = new HashSet<>(); StringTokenizer tokenizer = new StringTokenizer(input, ","); while (tokenizer.hasMoreTokens()) { ret.add(tokenizer.nextToken()); } return ret; } protected Map<String, Object> getConfigData(OrganizationConfig orgConfig, String itemsParam, boolean includeDefaults, boolean includeOverrides) { boolean itemsParamEmpty = itemsParam == null || itemsParam.isEmpty() || itemsParam.equals("*"); return orgConfig.getOrgConfigCustomMap(itemsParamEmpty ? null : getSetFromCommaSeparatedString(itemsParam), includeDefaults, includeOverrides); } @JSONP @RequireSystemAccess @GET @Path("config") public ApiResponse getConfig( @Context UriInfo ui, @QueryParam("items") @DefaultValue("") String itemsParam, @QueryParam("separate_defaults") @DefaultValue("false") boolean separateDefaults, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Get configuration for organization: {}", organization.getUuid()); } ApiResponse response = createApiResponse(); response.setAction( "get organization configuration" ); //response.setParams(ui.getQueryParameters()); OrganizationConfig orgConfig = management.getOrganizationConfigByUuid( organization.getUuid() ); if (separateDefaults) { response.setProperty("orgConfiguration", getConfigData(orgConfig, itemsParam, false, true)); response.setProperty("defaults", getConfigData(orgConfig, itemsParam, true, false)); } else { response.setProperty("configuration", getConfigData(orgConfig, itemsParam, true, true)); } return response; } @RequireSystemAccess @Consumes(MediaType.APPLICATION_JSON) @JSONP @PUT @Path("config") public ApiResponse putConfig( @Context UriInfo ui, Map<String, Object> json, @QueryParam("separate_defaults") @DefaultValue("false") boolean separateDefaults, @QueryParam("only_changed") @DefaultValue("false") boolean onlyChanged, @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Put configuration for organization: {}", organization.getUuid()); } ApiResponse response = createApiResponse(); response.setAction("put organization configuration"); //response.setParams(ui.getQueryParameters()); OrganizationConfig orgConfig = management.getOrganizationConfigByUuid( organization.getUuid() ); // validates JSON and throws IllegalArgumentException if invalid // exception will be handled up the chain orgConfig.addProperties(json, true); management.updateOrganizationConfig(orgConfig); // refresh orgConfig -- to pick up removed entries and defaults orgConfig = management.getOrganizationConfigByUuid( organization.getUuid() ); String itemsToReturn = ""; if (onlyChanged) { itemsToReturn = String.join(",", json.keySet()); } if (separateDefaults) { response.setProperty("orgConfiguration", getConfigData(orgConfig, itemsToReturn, false, true)); response.setProperty("defaults", getConfigData(orgConfig, itemsToReturn, true, false)); } else { response.setProperty( "configuration", getConfigData(orgConfig, itemsToReturn, true, true)); } return response; } /** Delete organization is not yet supported */ //@RequireSystemAccess @DELETE public ApiResponse deleteOrganization() throws Exception { throw new NotImplementedException(); } }