2010-12-29 14 views
8

Spring Security + CAS ile çalışırken, CAS'a, yani hizmet özelliğine gönderilen geri arama URL'si ile küçük bir yol bloğuna basmaya devam ediyorum. this ve this gibi bir dizi örneğe baktım ama hepsi sabit kodlanmış URL'ler kullanıyorlar (hatta Spring's CAS docs). Tipik bir kesikHizmetin URL'sini Spring'in CAS hizmet özelliklerinde doğru şekilde ayarlama

<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties"> 
    <property name="service" value="http://localhost:8080/click/j_spring_cas_security_check" /> 
    </bean> 

Birincisi, her yerde konuşlandırılabilir olmasını WAR istiyorum çünkü ben zor koduna sunucu adını veya bağlantı noktasını istemiyorum ve Başvurumu istemezler ... şuna benzer derleme zamanında belirli bir DNS girişine bağlanır. İkincisi, Spring'in neden uygulama bağlamını ve isteğin URL'sini otomatik olarak URL’yi oluşturmak için otomatik olarak algılayamadığını anlamıyorum. Bu ifadenin ilk kısmı hala duruyor, ancak Raghuram'ın aşağıda this link ile işaret ettiği gibi, güvenlik nedeniyle istemciden HTTP Ana Bilgisayar Başlığı'na güvenemeyiz.

İdeal olarak, URL'nin tam olarak kullanıcının istediği gibi olmasını isterim (isteğim, sitem.com'un bir alt alanı gibi geçerli olduğu sürece), bu nedenle sorunsuz veya en azından belirtmek istiyorum. Uygulamalarımın köküne göre bir yolum var ve Spring'in servis URL'sini anında belirlediğini görüyorum. aşağıdaki gibi bir şey ...

<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties"> 
    <property name="service" value="/my_cas_callback" /> 
    </bean> 

YA ...

<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties"> 
    <property name="service" value="${container.and.app.derived.value.here}" /> 
    </bean> 

bu olası veya kolay mı yoksa bariz kaçırdın? Bahar 2.6.5 İlkbaharda

+0

Yay 3 kullanıyorum; bahar güvenliği 3 docs –

+0

bağlantıya dikkat edin Belki de [bu bağlantı] (https://jira.springsource.org/browse/SEC-1374) sizin gereksiniminiz/probleminizle ilgili bazı bilgiler veriyor? – Raghuram

+0

Evet, kesinlikle bir şey öğrendim ve olası bir çözümü yok ettim. HTTP isteğine güvenemediğimden, hizmetin güvenli olması gereken dağıtım zamanında bazı türetilmiş değerler aracılığıyla ayarlanmasını istiyorum. –

cevap

4

Baharda 3 yöntem olarak org.springframework.security.ui.cas.ServiceProperties

uzanabilir ile birlikte kullanmak sonra CasAuthenticationProvider ve CasEntryPoint sınıflara göre bunun üstesinden ve olabilir kesindir ServiceProperties kendi sürümü ve daha dinamik bir uygulama ile getService() yöntemini geçersiz kılmak.

Ana makine üstbilgisini, gerekli etki alanını hesaplamak ve denetiminiz altındaki yalnızca etki alanlarının/alt etki alanlarının kullanıldığını doğrulayarak daha güvenli hale getirmek için kullanabilirsiniz. Ardından bu yapılandırılabilir bazı değerleri ekleyin.

Elbette uygulamanızın güvensiz olduğu konusunda riskli olmalısınız ... bu yüzden dikkatli olun.

O benzeyen sonunda olabilir:

<bean id="serviceProperties" class="my.ServiceProperties"> 
    <property name="serviceRelativeUrl" value="/my_cas_callback" /> 
    <property name="validDomainPattern" value="*.mydomain.com" /> 
</bean> 
+0

Bağlantılı belgeye göre, tüm bu yöntemleri final olarak etiketlenen Spring Security 3 kullanıyorum (http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/ güvenlik/cas/ServiceProperties.html) –

+0

Dolayısıyla, sorun bildirdiği gibi, CasAuthenticationProvider ve CasEntryPoint öğelerini alt sınıflara ayırabilir ve kendi Hizmet özellikleri sürümünü sağlayabilirsiniz. Ben daha açık – Pablojim

+0

yapmak için cevabı güncelledim muhtemelen doğru olduğunu düşünüyorum. Henüz bunu denemek için bir şansım olmadı ama ne zaman yaptığımı ve daha iyi bir cevap gelmediği sürece, bu en iyi cevap olacak gibi görünüyor. –

2

kullanım maven bir özellik yer tutucu ekleyin ve inşa sürecinde yapılandırmak

+0

veya bahar profillerini kullanın – chrismarx

0

CasjuthenticationProvider'ı Pablojim'in önerdiği gibi almayı denedim, ancak çözüm çok daha kolay! Bahar İfade Dili (SPEL) ile URL'yi dinamik olarak edinebilirsiniz.

Örnek: <property name="service" value="https://#{T(java.net.InetAddress).getLocalHost().getHostName()}:${application.port}${cas.service}/login/cascheck"/>

+0

Sadece bu yanıtla heyecanlanan herkes için açıklığa kavuşturmak için, ana bilgisayar adı bu istekleri, gerçek sunucu adı, istek üzerine ana bilgisayar adı değil. Farklı fiziksel sunucularda çalışan uygulamanın farklı sürümleri varsa, bu ideal olabilir – chrismarx

5

Bu biraz eski olduğunu biliyorum ama sadece bu çok sorunu çözmek zorunda kaldı ve gerçekten yeni desteler halinde bir şey bulamadı.

Aynı CAS hizmetini paylaşan birden fazla ortama sahibiz (think dev, qa, uat ve local development environment); Her ortama birden fazla URL'den (istemci tarafındaki web sunucusu üzerinden bir ters proxy üzerinden ve doğrudan arka uç sunucusuna) vurma yeteneğine sahibiz. Bu, tek bir URL'yi belirtmenin en iyi ihtimalle zor olduğu anlamına gelir. Belki de bunu yapmanın bir yolu var ama bir dinamik ServiceProperties.getService()'u kullanabiliyorum. URL'nin bir noktada ele geçirilmediğinden emin olmak için büyük olasılıkla bir çeşit sunucu sonek denetimi ekleyeceğim.

İşte

  1. geçersiz kılma CasAuthenticationFilter ... Ben ne olursa olsun güvenli kaynağa erişmek için kullanılan URL çalışan temel CAS akışını almak için bunu yaptık.
  2. CasAuthenticationProvider'u geçersiz kılın. ServiceProperties numaralı telefondan
  3. setAuthenticateAllArtifacts(true).

    @Configuration 
    @EnableWebSecurity 
    @EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true) 
    public class CasSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    

    Sadece her zamanki bahar yapılandırma fasulye:

İşte benim bahar yapılandırma fasulye uzun formudur.

@Value("${cas.server.url:https://localhost:9443/cas}") 
private String casServerUrl; 

@Value("${cas.service.validation.uri:/webapi/j_spring_cas_security_check}") 
private String casValidationUri; 

@Value("${cas.provider.key:whatever_your_key}") 
private String casProviderKey; 

Bazı harici yapılandırma parametreleri.

@Bean 
public ServiceProperties serviceProperties() { 
    ServiceProperties serviceProperties = new ServiceProperties(); 
    serviceProperties.setService(casValidationUri); 
    serviceProperties.setSendRenew(false); 
    serviceProperties.setAuthenticateAllArtifacts(true); 
    return serviceProperties; 
} 

önemli şey yukarıda setAuthenticateAllArtifacts(true) çağrıdır. Bu mevcut bir UserDetailsService

@Bean 
public CasAuthenticationProvider casAuthenticationProvider() { 
    CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider(); 
    casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService()); 
    casAuthenticationProvider.setServiceProperties(serviceProperties()); 
    casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator()); 
    casAuthenticationProvider.setKey(casProviderKey); 
    return casAuthenticationProvider; 
} 
için .. servis bilet doğrulayıcı kodlanmış ServiceProperties.getService() çağrı

@Bean 
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() { 
    return new Cas20ServiceTicketValidator(casServerUrl); 
} 

Standart bilet doğrulayıcı yerine AuthenticationDetailsSource uygulamayı kullanacaktır

@Resource 
private UserDetailsService userDetailsService; 

@Bean 
public AuthenticationUserDetailsService authenticationUserDetailsService() { 
    return new AuthenticationUserDetailsService() { 
     @Override 
     public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException { 
      String username = (token.getPrincipal() == null) ? "NONE_PROVIDED" : token.getName(); 
      return userDetailsService.loadUserByUsername(username); 
     } 
    }; 
} 

Standart kanca yapacak

Standart kimlik doğrulama sağlayıcısı

Burada
@Bean 
public CasAuthenticationFilter casAuthenticationFilter() throws Exception { 
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter(); 
    casAuthenticationFilter.setAuthenticationManager(authenticationManager()); 
    casAuthenticationFilter.setServiceProperties(serviceProperties()); 
    casAuthenticationFilter.setAuthenticationDetailsSource(dynamicServiceResolver()); 
    return casAuthenticationFilter; 
} 

Anahtar dynamicServiceResolver() ayarı ..

@Bean 
AuthenticationDetailsSource<HttpServletRequest, 
     ServiceAuthenticationDetails> dynamicServiceResolver() { 
    return new AuthenticationDetailsSource<HttpServletRequest, ServiceAuthenticationDetails>() { 
     @Override 
     public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) { 
      final String url = makeDynamicUrlFromRequest(serviceProperties()); 
      return new ServiceAuthenticationDetails() { 
       @Override 
       public String getServiceUrl() { 
        return url; 
       } 
      }; 
     } 
    }; 
} 

Dinamik makeDynamicUrlFromRequest() yönteminden hizmet url yaratmasıdır. Bu bit bilet doğrulaması üzerine kullanılır.

@Bean 
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() { 

    CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint() { 
     @Override 
     protected String createServiceUrl(final HttpServletRequest request, final HttpServletResponse response) { 
      return CommonUtils.constructServiceUrl(null, response, makeDynamicUrlFromRequest(serviceProperties()) 
        , null, serviceProperties().getArtifactParameter(), false); 
     } 
    }; 
    casAuthenticationEntryPoint.setLoginUrl(casServerUrl + "/login"); 
    casAuthenticationEntryPoint.setServiceProperties(serviceProperties()); 
    return casAuthenticationEntryPoint; 
} 

CAS, giriş ekranına yeniden yönlendirmek istediğinde, bu bölüm aynı dinamik URL oluşturucuyu kullanır.

private String makeDynamicUrlFromRequest(ServiceProperties serviceProperties){ 
    return "https://howeverYouBuildYourOwnDynamicUrl.com"; 
} 

Bu, ne yaparsanız yapın. Yalnızca yapılandırdığımız hizmetin URI'sini tutmak için ServiceProperties uygulamasından geçtim. Biz arka tarafında HATEAOS kullanmak ve benzeri bir uygulama vardır:

return UriComponentsBuilder.fromHttpUrl(
      linkTo(methodOn(ExposedRestResource.class) 
        .aMethodOnThatResource(null)).withSelfRel().getHref()) 
      .replacePath(serviceProperties.getService()) 
      .build(false) 
      .toUriString(); 

Düzenleme: Burada ben geçerli sunucu soneklerinin listesi için yaptık ..

private List<String> validCasServerHostEndings; 

@Value("${cas.valid.server.suffixes:company.com,localhost}") 
private void setValidCasServerHostEndings(String endings){ 
    validCasServerHostEndings = new ArrayList<>(); 
    for (String ending : StringUtils.split(endings, ",")) { 
     if (StringUtils.isNotBlank(ending)){ 
      validCasServerHostEndings.add(StringUtils.trim(ending)); 
     } 
    } 
} 

private String makeDynamicUrlFromRequest(ServiceProperties serviceProperties){ 
    UriComponents url = UriComponentsBuilder.fromHttpUrl(
      linkTo(methodOn(ExposedRestResource.class) 
        .aMethodOnThatResource(null)).withSelfRel().getHref()) 
      .replacePath(serviceProperties.getService()) 
      .build(false); 
    boolean valid = false; 
    for (String validCasServerHostEnding : validCasServerHostEndings) { 
     if (url.getHost().endsWith(validCasServerHostEnding)){ 
      valid = true; 
      break; 
     } 
    } 
    if (!valid){ 
     throw new AccessDeniedException("The server is unable to authenticate the requested url."); 
    } 
    return url.toString(); 
} 
+0

Bu yazıya bulabileceğiniz en yararlı bilgiler. Bu harika. Karmaşık sistemimizde böyle bir şeyi (aynı sebeplerden ötürü) uygulamakla gerçekten uğraştım. – Schaka

İlgili konular