2017-09-11 8 views
0

私たちはSpring 4.3.9.RELEASEとSpring Security 4.2.3.RELEASEを使用していますので、これらは私たちが見た最新のバージョンです。私たちには、Spring Web Securityを使用してAPIへのロールベースのアクセスを行う、RESTful(spring-mvc)バックエンドがあります。春のセキュリティテストの模擬カスタムユーザ

@RequestMapping(value = "/create", method = RequestMethod.POST, produces = "application/json", headers = "content-type=application/json") 
public @ResponseBody MyObjectEntity createMyObject(@RequestBody MyObjectEntity myObj) throws MyObjectException 
{ 
    UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
    CustomUser user = null; 
    if (userDetails instanceof CustomUser) 
    { 
     user = ((CustomUser) userDetails); 
    } 
    String email = user.getEmail(); 
    MyObjectEntity myObj = MyObjectService.createMyObject(myObj, email); 
    if (SecurityContextHolder.getContext().getAuthentication() != null) 
    { 
     SecurityContextHolder.getContext().setAuthentication(null); 
    } 
    return myObj; 
} 

私たちは、ユーザはユーザ名とパスワードを使用してウェブサイトからログインした知っている:

は、我々はこのようになりますコントローラを持っています。 UIにはトークンがあり、ヘッダーにそれを渡します。私たちのセキュリティはSiteMinderの例を使用しています。つまり、サードパーティに渡ってトークンを渡すUserDetailsS​​erviceがあり、ユーザー名、パスワード、およびユーザーの役割を取得できます。これは正常に機能しています。 我々は次のようにCustomUserDetailsS​​erviceを作成しました:

public class CustomUserDetailsService implements UserDetailsService 
{ 
    @Override 
    public UserDetails loadUserByUsername(String accessToken) throws 
     UsernameNotFoundException, 
     PreAuthenticatedCredentialsNotFoundException 
     { 
      // goto to third-party service to verify token 
      // get the Custom User and the user roles 
      // also get some extra data, so a custom user 
     } 
} 

をだから我々は、トークンが有効で設立された後、私たちは、サードパーティからの追加のユーザー情報を得ている、と私たちは、このために許可されている有効な役割を持っていますAPI ...コントローラ自体を実行することができます。また、このコードはSpring Security Contextから既存のユーザを守るための伝統的なものです。

UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
    CustomUser user = null; 
    if (userDetails instanceof CustomUser) 
    { 
     user = ((CustomUser) userDetails); 
    } 

実際には、私たちが読んだことから、これはカスタムユーザーとCustomUserDetailsがあるときに行う方法です。このコードでは、このユーザーの電子メールを取得したいと考えています。これは、Advanced REST Clientを使用して実際にAPIをテストするときにすべて機能します。私たちのQAはWebサイトに対して認証する必要があり、トークンをUIに戻してアクセストークンを取得し、Advanced REST Client(またはPostman)のヘッダーに入れて、これをすべて動作させます。

APIが終了したときにセキュリティコンテキストを無効にするコードもあります。

if (SecurityContextHolder.getContext().getAuthentication() != null) 
{ 
    SecurityContextHolder.getContext().setAuthentication(null); 
} 

実際のAPIは、実際の進歩とともに、これは素晴らしいです。 テストになると、いくつかのテストはセキュリティ保護されたコントローラに対して機能し、一部のテストでは機能しません。だから、ここではテストにコントローラを持っている:

@RequestMapping(value = "/{productId}", method = RequestMethod.GET, headers = "Accept=application/json") 
public @ResponseBody ProductEntity getProductById(@PathVariable("productId") long productId) 
{ 
    logger.debug("ProductController: getProductById: productId=" + productId); 
    CustomUser user = authenticate(); 
    ProductEntity productEntity = service.getById(productId); 
    logger.debug("ProductController: getProductById: productEntity=" + productEntity); 
    invalidateUser(); 
    return productEntity; 
} 

そして、ここではテストです:

@Test 
public void testMockGetProductByProductId() throws Exception 
{ 
    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(BASE_URL + "/1").with(user("testuser").roles("REGULAR_USER")); 
    this.mockMvc.perform(requestBuilder).andDo(print()).andExpect(status().isOk()); 
} 

我々はコントローラに到達しても、我々はCustomerUserセットを必要としないので、これは動作しますが、それは動作します。ロールが正しいロール(「REGULAR_USER」)であれば、それは機能し、ロールが正しくない場合は、403エラーが発生します。

私がトップに最初に投稿したコントローラを見ると、カスタムユーザーが設定されている必要があります。設定されていない場合は、そのメールを取得しようとすると失敗します。そこで、私たちは認証で擬似ユーザを設定する複数の方法を検討しています。コントローラに到達すると、そのCustomUserをすでにセキュリティコンテキストに置くことができます。

私はこれまでにこれまでに行ってきましたが、それはカスタムユーザーではなく標準のスプリングセキュリティユーザーを使用しているときでした。

セキュリティコンテキストにCustomUserを確実に設定できますが、コントローラに到達するとこのコードが実行されます。

// THIS WORKS 
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
    CustomUser user = null; 

    // This IF fails because; 
    // userDetails is of instance User (Spring Security User) 
    // and not CustomUser. 
    if (userDetails instanceof CustomUser) 
    { 
     user = ((CustomUser) userDetails); 
    } 

私たちのCustomUserための我々が持っているコードを追加してみましょう:

public class CustomUser implements UserDetails 
{ 

private static final long serialVersionUID = -6650061185298405641L; 
private String userName; 
private ArrayList<GrantedAuthority> authorities; 

private String firstName; 
private String middleName; 
private String lastName; 
private String email; 
private String phone; 
private String externalUserId; 

    // getters/setters 
    // toString 

} 

私は誰かが私の質問に答えることができることをここに十分な情報を入れたいと考えています。私はこの質問に役に立たない人にインターネットを精練して1日か2日過ごしました。回答のいくつかは、Spring 3およびそれ以前のSpring Security 3.xより少し古いものでした。それ以上の情報が必要な場合は、私に知らせてください。ありがとう!

私はUserDetailsを暗示するCustomUserDetailsが必要なのでしょうか?

もう一度おねがいします!

答えて

1

これはおそらくあなたの考えよりはるかに簡単です。

CustomUser userDetails = new CustomUser(); 
/* TODO: set username, authorities etc */ 
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(BASE_URL + "/1").with(user(userDetails)); 

これは、限り、あなたのCustomUserUserDetailsインターフェイスを実装として許可されています。

+0

うわー...結局のところ。それは簡単でした。また、CustomUserはUserDetailsインターフェイスを実装しています。 – tjholmes66

+0

あなたは 'user()'メソッドを呼び出すためにどの静的インポートを使用していますか?私はspring-test-4.3とSpring Security 4.2.3.RELEASEを使用していますが、問題を解決したり回避したりする可能性のあるインポートを解決しようと夢中になっています(例えば、org.springframework.security .test .... '、' @ WithMockUser'などの)。 – Antonio

+0

さて、私は最終的にそれを取得しました。これは、私が使用しているスプリングブートの新しいバージョンでは、依存関係 'org.springframework.security:spring-security-test:4.2.3.RELEASE'を_explicitly_する必要があります。 'spring-boot-starter-test:1.5.3'のPOMにもう含まれています – Antonio