KEYCLOAK-2593 Character set missing from responses and no content sniffing defense in place
This commit is contained in:
parent
8f2c5af7d1
commit
7342261dbe
12 changed files with 126 additions and 26 deletions
|
@ -26,7 +26,7 @@ public interface MigrationModel {
|
||||||
/**
|
/**
|
||||||
* Must have the form of major.minor.micro as the version is parsed and numbers are compared
|
* Must have the form of major.minor.micro as the version is parsed and numbers are compared
|
||||||
*/
|
*/
|
||||||
String LATEST_VERSION = "1.9.0";
|
String LATEST_VERSION = "1.9.2";
|
||||||
|
|
||||||
String getStoredVersion();
|
String getStoredVersion();
|
||||||
void setStoredVersion(String version);
|
void setStoredVersion(String version);
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.migration.migrators.MigrateTo1_6_0;
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_7_0;
|
import org.keycloak.migration.migrators.MigrateTo1_7_0;
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_8_0;
|
import org.keycloak.migration.migrators.MigrateTo1_8_0;
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
||||||
import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1;
|
import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
|
||||||
|
@ -92,6 +93,12 @@ public class MigrationModelManager {
|
||||||
}
|
}
|
||||||
new MigrateTo1_9_0().migrate(session);
|
new MigrateTo1_9_0().migrate(session);
|
||||||
}
|
}
|
||||||
|
if (stored == null || stored.lessThan(MigrateTo1_9_2.VERSION)) {
|
||||||
|
if (stored != null) {
|
||||||
|
logger.debug("Migrating older model to 1.9.2 updates");
|
||||||
|
}
|
||||||
|
new MigrateTo1_9_2().migrate(session);
|
||||||
|
}
|
||||||
|
|
||||||
model.setStoredVersion(MigrationModel.LATEST_VERSION);
|
model.setStoredVersion(MigrationModel.LATEST_VERSION);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* 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.keycloak.migration.migrators;
|
||||||
|
|
||||||
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
import org.keycloak.models.BrowserSecurityHeaders;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
|
||||||
|
public class MigrateTo1_9_2 {
|
||||||
|
|
||||||
|
public static final ModelVersion VERSION = new ModelVersion("1.9.2");
|
||||||
|
|
||||||
|
public void migrate(KeycloakSession session) {
|
||||||
|
for (RealmModel realm : session.realms().getRealms()) {
|
||||||
|
if (realm.getBrowserSecurityHeaders() != null) {
|
||||||
|
realm.getBrowserSecurityHeaders().put("xFrameOptions", "nosniff");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,13 +30,15 @@ public class BrowserSecurityHeaders {
|
||||||
public static final Map<String, String> defaultHeaders;
|
public static final Map<String, String> defaultHeaders;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, String> headerMap = new HashMap<String, String>();
|
Map<String, String> headerMap = new HashMap<>();
|
||||||
headerMap.put("xFrameOptions", "X-Frame-Options");
|
headerMap.put("xFrameOptions", "X-Frame-Options");
|
||||||
headerMap.put("contentSecurityPolicy", "Content-Security-Policy");
|
headerMap.put("contentSecurityPolicy", "Content-Security-Policy");
|
||||||
|
headerMap.put("xContentTypeOptions", "X-Content-Type-Options");
|
||||||
|
|
||||||
Map<String, String> dh = new HashMap<String, String>();
|
Map<String, String> dh = new HashMap<>();
|
||||||
dh.put("xFrameOptions", "SAMEORIGIN");
|
dh.put("xFrameOptions", "SAMEORIGIN");
|
||||||
dh.put("contentSecurityPolicy", "frame-src 'self'");
|
dh.put("contentSecurityPolicy", "frame-src 'self'");
|
||||||
|
dh.put("xContentTypeOptions", "nosniff");
|
||||||
|
|
||||||
defaultHeaders = Collections.unmodifiableMap(dh);
|
defaultHeaders = Collections.unmodifiableMap(dh);
|
||||||
headerAttributeMap = Collections.unmodifiableMap(headerMap);
|
headerAttributeMap = Collections.unmodifiableMap(headerMap);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
@ -64,6 +63,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.utils.FormMessage;
|
import org.keycloak.models.utils.FormMessage;
|
||||||
|
import org.keycloak.utils.MediaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -209,7 +209,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8_TYPE).language(locale).entity(result);
|
||||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
} catch (FreeMarkerException e) {
|
} catch (FreeMarkerException e) {
|
||||||
|
|
|
@ -61,8 +61,8 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.utils.FormMessage;
|
import org.keycloak.models.utils.FormMessage;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
|
import org.keycloak.utils.MediaType;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
@ -312,7 +312,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8).entity(result);
|
||||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||||
builder.header(entry.getKey(), entry.getValue());
|
builder.header(entry.getKey(), entry.getValue());
|
||||||
|
@ -413,7 +413,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String result = freeMarker.processTemplate(attributes, form, theme);
|
String result = freeMarker.processTemplate(attributes, form, theme);
|
||||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8_TYPE).language(locale).entity(result);
|
||||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||||
builder.header(entry.getKey(), entry.getValue());
|
builder.header(entry.getKey(), entry.getValue());
|
||||||
|
|
|
@ -17,17 +17,27 @@
|
||||||
package org.keycloak.services.resources;
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.theme.FreeMarkerUtil;
|
|
||||||
import org.keycloak.theme.Theme;
|
|
||||||
import org.keycloak.theme.ThemeProvider;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.common.util.MimeTypeUtil;
|
import org.keycloak.common.util.MimeTypeUtil;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.util.CacheControlUtil;
|
import org.keycloak.services.util.CacheControlUtil;
|
||||||
|
import org.keycloak.theme.FreeMarkerUtil;
|
||||||
|
import org.keycloak.theme.Theme;
|
||||||
|
import org.keycloak.theme.ThemeProvider;
|
||||||
|
import org.keycloak.utils.MediaType;
|
||||||
|
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.core.*;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
@ -64,7 +74,7 @@ public class WelcomeResource {
|
||||||
* @throws URISyntaxException
|
* @throws URISyntaxException
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Produces("text/html")
|
@Produces(MediaType.TEXT_HTML_UTF_8)
|
||||||
public Response getWelcomePage() throws URISyntaxException {
|
public Response getWelcomePage() throws URISyntaxException {
|
||||||
checkBootstrap();
|
checkBootstrap();
|
||||||
|
|
||||||
|
@ -127,7 +137,7 @@ public class WelcomeResource {
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/welcome-content/{path}")
|
@Path("/welcome-content/{path}")
|
||||||
@Produces("text/html")
|
@Produces(MediaType.TEXT_HTML_UTF_8)
|
||||||
public Response getResource(@PathParam("path") String path) {
|
public Response getResource(@PathParam("path") String path) {
|
||||||
try {
|
try {
|
||||||
InputStream resource = getTheme().getResourceAsStream(path);
|
InputStream resource = getTheme().getResourceAsStream(path);
|
||||||
|
|
|
@ -42,14 +42,13 @@ import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.services.Urls;
|
import org.keycloak.services.Urls;
|
||||||
|
import org.keycloak.utils.MediaType;
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import javax.ws.rs.ext.Providers;
|
import javax.ws.rs.ext.Providers;
|
||||||
|
@ -296,7 +295,7 @@ public class AdminConsole {
|
||||||
|
|
||||||
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
||||||
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
||||||
Response.ResponseBuilder builder = Response.status(Response.Status.OK).type(MediaType.TEXT_HTML).entity(result);
|
Response.ResponseBuilder builder = Response.status(Response.Status.OK).type(MediaType.TEXT_HTML_UTF_8).language(Locale.ENGLISH).entity(result);
|
||||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,10 @@ public class BrowserSecurityHeaderSetup {
|
||||||
public static Response.ResponseBuilder headers(Response.ResponseBuilder builder, RealmModel realm) {
|
public static Response.ResponseBuilder headers(Response.ResponseBuilder builder, RealmModel realm) {
|
||||||
for (Map.Entry<String, String> entry : realm.getBrowserSecurityHeaders().entrySet()) {
|
for (Map.Entry<String, String> entry : realm.getBrowserSecurityHeaders().entrySet()) {
|
||||||
String headerName = BrowserSecurityHeaders.headerAttributeMap.get(entry.getKey());
|
String headerName = BrowserSecurityHeaders.headerAttributeMap.get(entry.getKey());
|
||||||
if (headerName == null) continue;
|
if (headerName != null && entry.getValue() != null && entry.getValue().length() > 0) {
|
||||||
builder.header(headerName, entry.getValue());
|
builder.header(headerName, entry.getValue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
services/src/main/java/org/keycloak/utils/MediaType.java
Normal file
34
services/src/main/java/org/keycloak/utils/MediaType.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* 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.keycloak.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class MediaType {
|
||||||
|
|
||||||
|
public static final String TEXT_HTML_UTF_8 = "text/html; charset=utf-8";
|
||||||
|
public static final javax.ws.rs.core.MediaType TEXT_HTML_UTF_8_TYPE = new javax.ws.rs.core.MediaType("text", "html", "utf-8");
|
||||||
|
|
||||||
|
public static final String APPLICATION_JSON = javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||||
|
public static final javax.ws.rs.core.MediaType APPLICATION_JSON_TYPE = javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
|
||||||
|
|
||||||
|
public static final String APPLICATION_FORM_URLENCODED = javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
|
||||||
|
public static final javax.ws.rs.core.MediaType APPLICATION_FORM_URLENCODED_TYPE = javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED_TYPE;
|
||||||
|
|
||||||
|
}
|
|
@ -95,8 +95,11 @@ login-action-timeout.tooltip=Max time a user has to complete login related actio
|
||||||
headers=Headers
|
headers=Headers
|
||||||
brute-force-detection=Brute Force Detection
|
brute-force-detection=Brute Force Detection
|
||||||
x-frame-options=X-Frame-Options
|
x-frame-options=X-Frame-Options
|
||||||
click-label-for-info=Click on label link for more information. The default value prevents pages from being included via non-origin iframes.
|
x-frame-options-tooltip=Default value prevents pages from being included via non-origin iframes (click label for more information)
|
||||||
content-sec-policy=Content-Security-Policy
|
content-sec-policy=Content-Security-Policy
|
||||||
|
content-sec-policy-tooltip=Default value prevents pages from being included via non-origin iframes (click label for more information)
|
||||||
|
content-type-options=X-Content-Type-Options
|
||||||
|
content-type-options-tooltip=Default value prevents Internet Explorer and Google Chrome from MIME-sniffing a response away from the declared content-type (click label for more information)
|
||||||
max-login-failures=Max Login Failures
|
max-login-failures=Max Login Failures
|
||||||
max-login-failures.tooltip=How many failures before wait is triggered.
|
max-login-failures.tooltip=How many failures before wait is triggered.
|
||||||
wait-increment=Wait Increment
|
wait-increment=Wait Increment
|
||||||
|
|
|
@ -9,18 +9,25 @@
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
<fieldset class="border-top">
|
<fieldset class="border-top">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" for="xFrameOptions"><a href="http://tools.ietf.org/html/rfc7034">{{:: 'x-frame-options' | translate}}</a></label>
|
<label class="col-md-2 control-label" for="xFrameOptions"><a href="http://tools.ietf.org/html/rfc7034" target="_blank">{{:: 'x-frame-options' | translate}}</a></label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input class="form-control" id="xFrameOptions" type="text" ng-model="realm.browserSecurityHeaders.xFrameOptions">
|
<input class="form-control" id="xFrameOptions" type="text" ng-model="realm.browserSecurityHeaders.xFrameOptions">
|
||||||
</div>
|
</div>
|
||||||
<kc-tooltip>{{:: 'click-label-for-info' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'x-frame-options-tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" for="contentSecurityPolicy"><a href="http://www.w3.org/TR/CSP/">{{:: 'content-sec-policy' | translate}}</a></label>
|
<label class="col-md-2 control-label" for="contentSecurityPolicy"><a href="http://www.w3.org/TR/CSP/" target="_blank">{{:: 'content-sec-policy' | translate}}</a></label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input class="form-control" id="contentSecurityPolicy" type="text" ng-model="realm.browserSecurityHeaders.contentSecurityPolicy">
|
<input class="form-control" id="contentSecurityPolicy" type="text" ng-model="realm.browserSecurityHeaders.contentSecurityPolicy">
|
||||||
</div>
|
</div>
|
||||||
<kc-tooltip>{{:: 'click-label-for-info' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'content-sec-policy-tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="xContentTypeOptions"><a href="https://www.owasp.org/index.php/List_of_useful_HTTP_headers">{{:: 'content-type-options' | translate}}</a></label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input class="form-control" id="xContentTypeOptions" type="text" ng-model="realm.browserSecurityHeaders.xContentTypeOptions">
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'content-type-options-tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="form-group" data-ng-show="access.manageRealm">
|
<div class="form-group" data-ng-show="access.manageRealm">
|
||||||
|
|
Loading…
Reference in a new issue