001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.actuate.autoconfigure.endpoint.web;
018
019import java.time.Duration;
020import java.time.temporal.ChronoUnit;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.springframework.boot.context.properties.ConfigurationProperties;
025import org.springframework.boot.context.properties.PropertyMapper;
026import org.springframework.boot.convert.DurationUnit;
027import org.springframework.util.CollectionUtils;
028import org.springframework.web.cors.CorsConfiguration;
029
030/**
031 * Configuration properties for web endpoints' CORS support.
032 *
033 * @author Andy Wilkinson
034 * @since 2.0.0
035 */
036@ConfigurationProperties(prefix = "management.endpoints.web.cors")
037public class CorsEndpointProperties {
038
039        /**
040         * Comma-separated list of origins to allow. '*' allows all origins. When not set,
041         * CORS support is disabled.
042         */
043        private List<String> allowedOrigins = new ArrayList<>();
044
045        /**
046         * Comma-separated list of methods to allow. '*' allows all methods. When not set,
047         * defaults to GET.
048         */
049        private List<String> allowedMethods = new ArrayList<>();
050
051        /**
052         * Comma-separated list of headers to allow in a request. '*' allows all headers.
053         */
054        private List<String> allowedHeaders = new ArrayList<>();
055
056        /**
057         * Comma-separated list of headers to include in a response.
058         */
059        private List<String> exposedHeaders = new ArrayList<>();
060
061        /**
062         * Whether credentials are supported. When not set, credentials are not supported.
063         */
064        private Boolean allowCredentials;
065
066        /**
067         * How long the response from a pre-flight request can be cached by clients. If a
068         * duration suffix is not specified, seconds will be used.
069         */
070        @DurationUnit(ChronoUnit.SECONDS)
071        private Duration maxAge = Duration.ofSeconds(1800);
072
073        public List<String> getAllowedOrigins() {
074                return this.allowedOrigins;
075        }
076
077        public void setAllowedOrigins(List<String> allowedOrigins) {
078                this.allowedOrigins = allowedOrigins;
079        }
080
081        public List<String> getAllowedMethods() {
082                return this.allowedMethods;
083        }
084
085        public void setAllowedMethods(List<String> allowedMethods) {
086                this.allowedMethods = allowedMethods;
087        }
088
089        public List<String> getAllowedHeaders() {
090                return this.allowedHeaders;
091        }
092
093        public void setAllowedHeaders(List<String> allowedHeaders) {
094                this.allowedHeaders = allowedHeaders;
095        }
096
097        public List<String> getExposedHeaders() {
098                return this.exposedHeaders;
099        }
100
101        public void setExposedHeaders(List<String> exposedHeaders) {
102                this.exposedHeaders = exposedHeaders;
103        }
104
105        public Boolean getAllowCredentials() {
106                return this.allowCredentials;
107        }
108
109        public void setAllowCredentials(Boolean allowCredentials) {
110                this.allowCredentials = allowCredentials;
111        }
112
113        public Duration getMaxAge() {
114                return this.maxAge;
115        }
116
117        public void setMaxAge(Duration maxAge) {
118                this.maxAge = maxAge;
119        }
120
121        public CorsConfiguration toCorsConfiguration() {
122                if (CollectionUtils.isEmpty(this.allowedOrigins)) {
123                        return null;
124                }
125                PropertyMapper map = PropertyMapper.get();
126                CorsConfiguration configuration = new CorsConfiguration();
127                map.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins);
128                map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty)
129                                .to(configuration::setAllowedHeaders);
130                map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty)
131                                .to(configuration::setAllowedMethods);
132                map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty)
133                                .to(configuration::setExposedHeaders);
134                map.from(this::getMaxAge).whenNonNull().as(Duration::getSeconds)
135                                .to(configuration::setMaxAge);
136                map.from(this::getAllowCredentials).whenNonNull()
137                                .to(configuration::setAllowCredentials);
138                return configuration;
139        }
140
141}