001/*******************************************************************************
002 * Copyright 2017 The MIT Internet Trust Consortium
003 *
004 * Portions copyright 2011-2013 The MITRE Corporation
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *******************************************************************************/
018package org.mitre.openid.connect.web;
019
020import java.io.IOException;
021import java.io.Reader;
022import java.security.Principal;
023import java.text.SimpleDateFormat;
024import java.util.Date;
025import java.util.List;
026
027import javax.servlet.http.HttpServletResponse;
028
029import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
030import org.mitre.openid.connect.service.MITREidDataService;
031import org.mitre.openid.connect.service.impl.MITREidDataService_1_3;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034import org.springframework.beans.factory.annotation.Autowired;
035import org.springframework.http.MediaType;
036import org.springframework.security.access.prepost.PreAuthorize;
037import org.springframework.stereotype.Controller;
038import org.springframework.ui.Model;
039import org.springframework.web.bind.annotation.RequestMapping;
040import org.springframework.web.bind.annotation.RequestMethod;
041
042import com.google.common.collect.ImmutableList;
043import com.google.gson.stream.JsonReader;
044import com.google.gson.stream.JsonToken;
045import com.google.gson.stream.JsonWriter;
046
047/**
048 * API endpoint for importing and exporting the current state of a server.
049 * Includes all tokens, grants, whitelists, blacklists, and clients.
050 *
051 * @author jricher
052 *
053 */
054@Controller
055@RequestMapping("/" + DataAPI.URL)
056@PreAuthorize("hasRole('ROLE_ADMIN')") // you need to be an admin to even think about this -- this is a potentially dangerous API!!
057public class DataAPI {
058
059        public static final String URL = RootController.API_URL + "/data";
060
061        /**
062         * Logger for this class
063         */
064        private static final Logger logger = LoggerFactory.getLogger(DataAPI.class);
065
066        private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
067
068        @Autowired
069        private ConfigurationPropertiesBean config;
070
071        @Autowired
072        private List<MITREidDataService> importers;
073
074        private List<String> supportedVersions = ImmutableList.of(
075                        MITREidDataService.MITREID_CONNECT_1_0,
076                        MITREidDataService.MITREID_CONNECT_1_1,
077                        MITREidDataService.MITREID_CONNECT_1_2,
078                        MITREidDataService.MITREID_CONNECT_1_3);
079
080        @Autowired
081        private MITREidDataService_1_3 exporter;
082
083        @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
084        public String importData(Reader in, Model m) throws IOException {
085
086                JsonReader reader = new JsonReader(in);
087
088                reader.beginObject();
089
090                while (reader.hasNext()) {
091                        JsonToken tok = reader.peek();
092                        switch (tok) {
093                                case NAME:
094                                        String name = reader.nextName();
095
096                                        if (supportedVersions.contains(name)) {
097                                                // we're working with a known data version tag
098                                                for (MITREidDataService dataService : importers) {
099                                                        // dispatch to the correct service
100                                                        if (dataService.supportsVersion(name)) {
101                                                                dataService.importData(reader);
102                                                                break;
103                                                        }
104                                                }
105                                        } else {
106                                                // consume the next bit silently for now
107                                                logger.debug("Skipping value for " + name); // TODO: write these out?
108                                                reader.skipValue();
109                                        }
110                                        break;
111                                case END_OBJECT:
112                                        break;
113                                case END_DOCUMENT:
114                                        break;
115                        }
116                }
117
118                reader.endObject();
119
120                return "httpCodeView";
121        }
122
123        @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
124        public void exportData(HttpServletResponse resp, Principal prin) throws IOException {
125
126                resp.setContentType(MediaType.APPLICATION_JSON_VALUE);
127
128                // this writer puts things out onto the wire
129                JsonWriter writer = new JsonWriter(resp.getWriter());
130                writer.setIndent("  ");
131
132                try {
133
134                        writer.beginObject();
135
136                        writer.name("exported-at");
137                        writer.value(dateFormat.format(new Date()));
138
139                        writer.name("exported-from");
140                        writer.value(config.getIssuer());
141
142                        writer.name("exported-by");
143                        writer.value(prin.getName());
144
145                        // delegate to the service to do the actual export
146                        exporter.exportData(writer);
147
148                        writer.endObject(); // end root
149                        writer.close();
150
151                } catch (IOException e) {
152                        logger.error("Unable to export data", e);
153                }
154        }
155
156}