1

Wir erstellen einen REST-Ressourcenserver (eine Java-Beispielanwendung), den wir mithilfe eines Mechanismus zur Identitätsweitergabe schützen möchten, der von RFC7662 definiert wird und im MITREID Connect-Projekt verfügbar ist. Wir haben beide Konfigurationsmethoden, das XML-Setup, sowie das Annotations-basierte Setup getestet, das der Ressourcen-Server-Klasse hinzugefügt wurde (siehe unten angehängter Beispielcode).So schützen Sie eine Ressource mit Spring Security OAuth2 und MITREID Connect Introspect?

Unser Test zeigt die erfolgreiche Initialisierung der Spring Security-Routine, aber es ist uns nicht gelungen, die Bearer-Token-Passage durch den Autorisierungsheader auszulösen. Die Anfrage und die Ressource werden erfolgreich ausgeführt, es wurde jedoch keine Token-Analyse und Introspect-Validierung durchgeführt. Bitte überprüfen Sie die unten aufgeführten Konfigurationseinstellungen und Protokolle.

Unterstützung ist willkommen, das fehlende Kabel zwischen den Komponenten zu isolieren (Spring Security, Spring Oauth2 und Mitreid Connect Introspect).

Setup-Datei: spring-security.xml

<?xml version="1.0" encoding="UTF-8"?> 

http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.1.xsd ">

<sec:http pattern="/css/**" security="none" /> 
<sec:http pattern="/js/**" security="none" /> 

<sec:http auto-config="true" use-expressions="true" 
    disable-url-rewriting="true" entry-point-ref="oauthAuthenticationEntryPoint" 
    pattern="/rest/service/sample/restService"> 

    <sec:custom-filter before="PRE_AUTH_FILTER" ref="resourceServerFilter" /> 
</sec:http> 

<sec:authentication-manager alias="authenticationManager"> 
</sec:authentication-manager> 

<!-- Begin OAuth2 Introspect configuration --> 


<bean id="oauthAuthenticationEntryPoint" 
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"> 
    <property name="realmName" value="W3IDRealm" /> 
</bean> 

<oauth:resource-server id="resourceServerFilter" 
    token-services-ref="introspectingService" /> 

<bean id="introspectingService" 
    class="org.mitre.oauth2.introspectingfilter.IntrospectingTokenService"> 
    <property name="introspectionConfigurationService" ref="staticIntrospectionConfigurationService"> 
    </property> 
</bean> 

    <!-- <oauth:resource 
    id="protectedResource" 
    access-token-uri="${oidc.tokenEndpointUri}" 
    client-secret="${oidc.clientSecret}" 
    client-id="${oidc.clientId}"></oauth:resource> --> 

<bean 
    class="org.mitre.oauth2.introspectingfilter.service.impl.StaticIntrospectionConfigurationService" 
    id="staticIntrospectionConfigurationService"> 
    <property name="introspectionUrl" value="${oidc.introspectEndpointUri}" /> 
    <property name="clientConfiguration"> 
     <bean class="org.mitre.oauth2.model.RegisteredClient"> 
      <property name="clientId" value="${oidc.clientId}" /> 
      <property name="clientSecret" value="${oidc.clientSecret}" /> 
     </bean> 
    </property> 
    <!-- <property name="introspectionAuthorityGranter"> 
     <bean class="org.mitre.oauth2.introspectingfilter.SimpleIntrospectionAuthorityGranter"> 
      <property name="authorities"> 
       <value>ROLE_API</value> 
      </property> 
     </bean> 
    </property> --> 
</bean> 

resource.java

package com.red.sampleoidcservice; 

import java.util.Map; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.ResponseBody; 

@Controller 
@EnableWebSecurity 
@Configuration 
@EnableResourceServer 
public class RestController { 

    private static final Logger logger = LoggerFactory.getLogger(RestController.class); 

    @RequestMapping(value = "/restService", method = RequestMethod.POST) 
    public @ResponseBody String restService(HttpServletRequest request, HttpServletResponse respose) { 

     logger.info("Calling rest service"); 

     String requestToString = request.toString(); 

     String headerType = request.getHeader("Content-Type"); 
     String headerAuth = request.getHeader("Authorization"); 

     Map map = request.getParameterMap(); 

     String attributes = request.getAttributeNames().toString(); 

     // String someParam = request.getParameter("someParam"); 

     return "{\"status\":\"OK\"}"; 
    } 

    protected static class ResourceServer extends ResourceServerConfigurerAdapter { 

     @Override 
     public void configure(HttpSecurity http) throws Exception { 
      http.requestMatchers().antMatchers("/rest/service/sample/restService").and().authorizeRequests() 
        .anyRequest().access("#oauth2.hasScope('read')"); 
     } 

     @Override 
     public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 
      resources.resourceId("W3IDRealm"); 
     } 
    } 

} 

post.java

// HTTP POST request 
private void sendPost(String token) throws Exception { 

    try { 

     token = "blablabla"; 

     TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
       return new X509Certificate[0]; 
      } 

      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { 
      } 

      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { 
      } 
     } }; 

     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

     CloseableHttpClient httpClient = HttpClientBuilder.create().build(); 

     SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sc, new String[] { "TLSv1.2" }, null, 
       org.apache.http.conn.ssl.SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); 

     httpClient = HttpClients.custom().setSSLSocketFactory(f).build(); 

     HttpPost postRequest = new HttpPost("https://localhost:9444/rest/service/sample/restService"); 

     postRequest.addHeader("Content-Type", "application/x-www-form-urlencoded"); 

     List<NameValuePair> formparams = new ArrayList<NameValuePair>(); 
     formparams.add(new BasicNameValuePair("client_id", clientId)); 
     formparams.add(new BasicNameValuePair("client_secret", clientSecret)); 
     formparams.add(new BasicNameValuePair("token", token)); 

     UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "utf-8"); 
     postRequest.setEntity(entity); 

     postRequest.setHeader("Authorization", "Bearer " + token + ""); 

     HttpResponse response = httpClient.execute(postRequest, new BasicHttpContext()); 

     int statusCode = response.getStatusLine().getStatusCode(); 

     logger.info("HTTP status code : " + statusCode); 

    } catch (Exception e) { 
     logger.error(e.getMessage()); 
    } 
} 

Trace:

INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'appServlet': initialization completed in 5872 ms 

DEBUG: org.springframework.web.servlet.DispatcherServlet - Servlets 'appServlet' konfiguriert erfolgreich DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Hinzufügen von [servletConfigInitParams] PropertySource mit niedrigstem Suche Vorrang DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Hinzufügen von [servletContextInitParams] PropertySource mit der niedrigsten Suchpräzedenz DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Hinzufügen von [jndiProperties] PropertySource mit der niedrigsten Suchpriorität DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Hinzufügen von [systemProperties] PropertySource mit lowe st Suche Vorrang DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Hinzufügen von [systemEnvironment] PropertySource mit niedrigstem Suche Vorrang DEBUG: org.springframework.web.context.support.StandardServletEnvironment - Initialized StandardServletEnvironment mit PropertySources [servletConfigInitParams, servletContextInitParams , jndiProperties, systemProperties, systemEnvironment] DEBUG: org.springframework.web.filter.DelegatingFilterProxy - Initialisierungsfilter 'springSecurityFilterChain' DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Zurückgeben gecachten Instanz von Singletons bean 'org.springframework.security.filterChainProxy' DEBUG: org.springframework.web.filter.DelegatingFilterProxy - Filter 'springSecurityFilterChain' konfiguriert erfolgreich DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet mit Name 'appServlet' Verarbeitung POST-Anfrage für [/ Rest/Service/Probe/RestService] DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Nachschlagen Handler-Methode für Pfad/RestService DEBUG: org .springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Zurückgegebene Prozedur [public java.lang.String com.red.sampleoidcservice.RestController.restService (javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)] DEBUG: org.springfram ework.beans.factory.support.DefaultListableBeanFactory - Rückgabe der zwischengespeicherten Instanz der Singleton-Bean 'restController' INFO: com.red.sampleoidcservice.RestController - Aufruf des Restdienstes DEBUG: org.springframework.web.servlet.mvc.method.annotation. RequestResponseBodyMethodProcessor - Geschrieben [{"status": "OK"}] als "text/plain" mit [[email protected]12d551] DEBUG: org.springframework.web.servlet.DispatcherServlet - Null ModelAndView zurückgegeben an DispatcherServlet mit dem Namen 'appServlet': Annahme, dass HandlerAdapter die Bearbeitung der Anfrage abgeschlossen hat DEBUG: org.springframework.web.servlet.DispatcherServlet - Anfrage erfolgreich abgeschlossen DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Zurückgegebene zwischengespeicherte Instanz der Singleton-Bean 'delegatingApplicationListener'

Lösung gefunden

Konfiguration mit Annotation

/******************************************************************************* 
* Copyright 2014 The MITRE Corporation 
* and the MIT Kerberos and Internet Trust Consortium 
* 
* 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 com.RED.sampleoidcservice; 

import java.io.IOException; 
import java.security.Principal; 
import java.util.Locale; 
import java.util.Map; 

import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.mitre.oauth2.introspectingfilter.IntrospectingTokenService; 
import org.mitre.oauth2.introspectingfilter.service.impl.StaticIntrospectionConfigurationService; 
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod; 
import org.mitre.oauth2.model.RegisteredClient; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.http.HttpMethod; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor; 
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 
import org.springframework.security.web.util.matcher.RequestMatcher; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.ResponseBody; 
import org.springframework.web.filter.OncePerRequestFilter; 
import org.springframework.web.servlet.ModelAndView; 

@Controller 
@EnableWebSecurity 
@Configuration 
@EnableResourceServer // [2] 
@ComponentScan({ "com.RED.sampleoidcservice" }) 
public class ResourceServer extends ResourceServerConfigurerAdapter { 

    private static final Logger logger = LoggerFactory.getLogger(ResourceServer.class); 

    @Value("${oidc.jwks.keys}") 
    private String jwksString; 

    @Value("${oidc.introspectEndpointUri}") 
    private String introspectURL; 

    @Value("${oidc.clientId}") 
    private String clientId; 

    @Value("${oidc.clientSecret}") 
    private String clientSecret; 

    IntrospectingTokenService introspectTokenService = new IntrospectingTokenService(); 

    @RequestMapping(value = "/", method = RequestMethod.GET) 
    public ModelAndView modelHome(Locale locale, Principal p) { 

     logger.info("Initializing service resource"); 

     ModelAndView model = new ModelAndView("/home.tiles"); 
     return model; 
    } 

    @RequestMapping(value = "/jwk", method = RequestMethod.GET, produces = "application/json") 
    public @ResponseBody String jwk() { 
     return jwksString; 
    } 

    @RequestMapping(value = "/restService", method = RequestMethod.POST) 
    public @ResponseBody String restService(HttpServletRequest request, HttpServletResponse respose) { 

     logger.info("Calling rest service"); 

     String requestToString = request.toString(); 

     String headerType = request.getHeader("Content-Type"); 
     String headerAuth = request.getHeader("Authorization"); 

     String token = headerAuth.split(" ")[1]; 

     // introspectTokenService.readAccessToken(token); 

     Map map = request.getParameterMap(); 

     String attributes = request.getAttributeNames().toString(); 

     // String someParam = request.getParameter("someParam"); 

     return "{\"status\":\"OK\"}"; 
    } 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 
     http.requestMatcher(new OAuthRequestedMatcher()) 
     .authorizeRequests() 
      .antMatchers(HttpMethod.OPTIONS).permitAll() 
      .anyRequest().authenticated(); 
//  http.addFilterBefore(new TokenExtractorFilter(), BasicAuthenticationFilter.class).requestMatchers() 
//    .antMatchers("/rest/service/sample/restService").and().authorizeRequests().anyRequest() 
//    .access("ROLE_API"); 
    } 

    @Override 
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 
     resources.resourceId("W3IDRealm"); 
     resources.tokenExtractor(new BearerTokenExtractor()); 

     StaticIntrospectionConfigurationService introspectConfig = new StaticIntrospectionConfigurationService(); 

     introspectConfig.setIntrospectionUrl(introspectURL); 

     RegisteredClient client = new RegisteredClient(); 
     client.setClientId(clientId); 
     client.setClientSecret(clientSecret); 
     client.setTokenEndpointAuthMethod(AuthMethod.NONE); 

     introspectConfig.setClientConfiguration(client); 

     introspectTokenService.setIntrospectionConfigurationService(introspectConfig); 

     resources.tokenServices(introspectTokenService); 
    } 

    private static class OAuthRequestedMatcher implements RequestMatcher { 

     public boolean matches(HttpServletRequest request) { 

      String auth = request.getHeader("Authorization"); 
      // Determine if the client request contained an OAuth Authorization 
      boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer"); 
      boolean haveAccessToken = request.getParameter("access_token")!=null; 
      return haveOauth2Token || haveAccessToken; 
     } 

    } 

    class TokenExtractorFilter extends OncePerRequestFilter implements Filter, InitializingBean { 

     @Override 
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 

      //UserDetails details = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

      BearerTokenExtractor bte = new BearerTokenExtractor(); 

      String mytoken = bte.extract(request).toString(); 

      logger.info("Filter activated"); 

     } 

    } 

} 

Antwort

1

Ich habe eine Lösung mit einer Anmerkung basierte Konfiguration veröffentlicht, die uns geholfen haben, die Strömungs Details zu debuggen mit Hilfe von Java-Breakpoints. Die Validierung des OAuth2-Bearer-Tokens mit/introspect funktioniert jetzt. Dank aller von MITREID gelieferten Debug-Unterstützung. Sehen Sie sich die Codelösung an, die im letzten Abschnitt des oben gezeigten Berichts angezeigt wird.

Verwandte Themen