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}