Spring Security 使い方メモ　Run-As


:::note warn
Spring Security は 5.4 以降、設定の書き方に大幅な変更が入っています。
詳しくは @suke_masa さんの [Spring Security 5.7でセキュリティ設定の書き方が大幅に変わる件 - Qiita](https://qiita.com/suke_masa/items/908805dd45df08ba28d8) を参照してください。
:::


[基礎・仕組み的な話](http://qiita.com/opengl-8080/items/c105152c9ca48509bd0c)
[認証・認可の話](http://qiita.com/opengl-8080/items/032ed0fa27a239bdc1cc)
[Remember-Me の話](http://qiita.com/opengl-8080/items/7c34053c74448d39e8f5)
[CSRF の話](http://qiita.com/opengl-8080/items/3720ed415c2df26251a7)
[セッション管理の話](http://qiita.com/opengl-8080/items/ad9159910501d1989876)
[レスポンスヘッダーの話](http://qiita.com/opengl-8080/items/4e800eb6990653b0395c)
[メソッドセキュリティの話](http://qiita.com/opengl-8080/items/76715fd3a92b6ca680d0)
[CORS の話](http://qiita.com/opengl-8080/items/db0aa1ec0be36886953b)
[ACL の話](http://qiita.com/opengl-8080/items/24a3118ef36bcf55ba71)
[テストの話](http://qiita.com/opengl-8080/items/eaa8f4eb9286a3df7986)
[MVC, Boot との連携の話](http://qiita.com/opengl-8080/items/4824d4a8c012f7ec53db)

番外編
[Spring Security にできること・できないこと](http://qiita.com/opengl-8080/items/6dc37f8b77abb5ae1642)

# Hello World
## 実装
```java:MyRunAsService.java
package sample.spring.security.service;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

public class MyRunAsService {
    
    @Secured({"ROLE_USER", "RUN_AS_HOGE", "RUN_AS_FUGA"})
    public void secured() {
        this.printAuthorities("secured");
    }
    
    public void nonSecured() {
        this.printAuthorities("nonSecured");
    }
    
    public void printAuthorities(String tag) {
        System.out.println("[" + tag + "]");
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        System.out.println("Authentication.class = " + auth.getClass());
        auth.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .forEach(System.out::println);
    }
}
```

- `secured()` メソッドは `@Secured` でアノテートしている
- `nonSecured()` メソッドはアノテーションなし
- `printAuthorities()` メソッドは、ログイン中のユーザに付与された権限を全て表示する


```java:RunAsTestServlet.java
package sample.spring.security.servlet;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.service.MyRunAsService;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/run-as/*")
public class RunAsTestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
        MyRunAsService service = context.getBean(MyRunAsService.class);

        service.printAuthorities("メソッド呼び出し前");
        
        if ("/secured".equals(req.getPathInfo())) {
            service.secured();
        } else {
            service.nonSecured();
        }

        service.printAuthorities("メソッド呼び出し後");
    }
}
```

- `/run-as/secured` にアクセスがあったら、 `MyRunAsService` の `secured()` メソッドを実行する
- それ以外のパスにリクエストがあったら、 `nonSecured()` メソッドを実行する
- 各メソッドの実行前後でも、ログインユーザの権限を表示させる


**namespace**

```xml:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security.xsd">

    <bean class="sample.spring.security.service.MyRunAsService" />

    <bean id="runAsManager"
          class="org.springframework.security.access.intercept.RunAsManagerImpl">
        <property name="key" value="foo" />
    </bean>

    <bean id="runAsAuthenticationProvider"
          class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
        <property name="key" value="foo" />
    </bean>
    
    <sec:global-method-security secured-annotations="enabled" run-as-manager-ref="runAsManager" />
    
    <sec:http>
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="isAuthenticated()" />
        <sec:form-login />
        <sec:logout />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user name="hoge" password="hoge" authorities="ROLE_USER" />
            </sec:user-service>
        </sec:authentication-provider>
        
        <sec:authentication-provider ref="runAsAuthenticationProvider" />
    </sec:authentication-manager>
</beans>
```

**Java Configuration**

```java:MyGlobalMethodSecurityConfig.java
package sample.spring.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;

@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true)
public class MyGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    public static final String RUN_AS_KEY = "foo";

    @Override
    protected RunAsManager runAsManager() {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey(RUN_AS_KEY);
        return runAsManager;
    }
}
```

```java:MySpringSecurityConfig.java
package sample.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.security.access.intercept.RunAsImplAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import sample.spring.security.service.MyRunAsService;

@EnableWebSecurity
@Import(MyGlobalMethodSecurityConfig.class)
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
        provider.setKey(MyGlobalMethodSecurityConfig.RUN_AS_KEY);
        
        auth.authenticationProvider(provider)
            .inMemoryAuthentication()
                .withUser("hoge")
                .password("hoge")
                .authorities("ROLE_USER");
    }
    
    @Bean
    public MyRunAsService myRunAsService() {
        return new MyRunAsService();
    }
}
```

## 動作確認
`/run-as/secured` にアクセス

```text:サーバーコンソール出力
[メソッド呼び出し前]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[secured]
Authentication.class = class org.springframework.security.access.intercept.RunAsUserToken
ROLE_RUN_AS_HOGE
ROLE_RUN_AS_FUGA
ROLE_USER

[メソッド呼び出し後]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER
```

`/run-as/nonSecured` にアクセス

```text:サーバーコンソール出力
[メソッド呼び出し前]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[nonSecured]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[メソッド呼び出し後]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER
```

- `secured()` メソッドのときだけ、 `ROLE_RUN_AS_HOGE`, `ROLE_RUN_AS_FUGA` の権限が付与されている
- また、 `Authentication` の実体が `RunAsUserToken` に切り替わっている

## 説明
- Run-As の仕組みを使うと、特定のセキュアオブジェクトが実行されている間だけ、任意の権限を一時的に追加することができる

### RunAsManager の実装クラスを用意する
```xml:applicationContext.xml
    <bean id="runAsManager"
          class="org.springframework.security.access.intercept.RunAsManagerImpl">
        <property name="key" value="foo" />
    </bean>
```

- Run-As の具体的な処理は `RunAsManager` が行う
- Spring Security はデフォルト実装として `RunAsManagerImpl` を用意しているので、これを用意する
- プロパティ `key` に、任意の文字列を指定しておく（詳細は後述）

### RunAsManager を SecurityInterceptor に適用する
```xml:applicationContext.xml
    <sec:global-method-security secured-annotations="enabled" run-as-manager-ref="runAsManager" />
```

- `RunAsManager` を `<global-method-security>` の `run-as-manager-ref` 属性に指定する
- また、 `secured-annotations` を有効にしておく(`@Secured` アノテーションが使えるようになる)

```java:MyGlobalMethodSecurityConfig.java
@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true)
public class MyGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    public static final String RUN_AS_KEY = "foo";

    @Override
    protected RunAsManager runAsManager() {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey(RUN_AS_KEY);
        return runAsManager;
    }
}
```

- Java Configuration の場合は、 `GlobalMethodSecurityConfiguration` を継承したクラスを設定クラスとして用意し、 `runAsManager()` メソッドをオーバーライドする
    - `secured-annotations` に対応する設定は、 `@EnableGlobalMethodSecurity` の `securedEnabled` で指定

### RunAsImplAuthenticationProvider を用意する
```xml:applicationContext.xml
    <bean id="runAsAuthenticationProvider"
          class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
        <property name="key" value="foo" />
    </bean>

    <sec:authentication-manager>
        ...
        <sec:authentication-provider ref="runAsAuthenticationProvider" />
    </sec:authentication-manager>
```

- つづいて `RunAsImplAuthenticationProvider` を定義し、 `AuthenticationProvider` の並びに追加する
- `RunAsImplAuthenticationProvider` の `key` プロパティには、 `RunAsManagerImpl` で設定したのと同じ値を設定しておく

### 追加する権限を定義する
```java:MyRunAsService.java
    @Secured({"ROLE_USER", "RUN_AS_HOGE", "RUN_AS_FUGA"})
    public void secured() {
        this.printAuthorities("secured");
    }
```

- 最後に権限の追加を定義する部分
- `@Secured` アノテーションの `value` で、次の値を設定する
    1. アノテート対象を実行するために必要となる権限（ここでは `ROLE_USER`）
        - `@Secured` 自体はメソッドセキュリティのためのアノテーションなので、このメソッドを実行するために必要となる定義を指定しなければならない
        - `secured-annotations="enabled"` で `@Secured` を有効にすると、 `MethodSecurityIntercpetor` が使用する `Voter` は `RoleVoter` と `AuthenticatedVoter` になる
        - なので、これらの `Voter` に合わせた形で指定しなければならない（式ベースではない）
            - `RoleVoter` は、 `ROLE_` で始まる値が指定された場合に、ユーザが同様の権限（ロール）を与えられているかチェックする
            - `AuthenticatedVoter` は [定数で指定された３つのいずれか](http://docs.spring.io/autorepo/docs/spring-security/4.2.1.RELEASE/apidocs/org/springframework/security/access/vote/AuthenticatedVoter.html) を指定する
    2. Run-As で付加する権限（ここでは `RUN_AS_HOGE` と `RUN_AS_FUGA`）
        - 付加する権限は `RUN_AS_` で始まる形にする
        - 実際にユーザに付加される権限は、 `ROLE_` が頭についた形になる（`RUN_AS_HOGE` は `ROLE_RUN_AS_HOGE` になる）

# 使いどころは？
公式リファレンスには、リモートの Web サービスを呼び出すときに便利、みたいなことが書かれていたが、正直意味は分からなかった。

> these run-as replacements are particularly useful when calling remote web services
> （翻訳）
> Run-As の置き換えは、特にリモートの Web サービスを呼ぶときに便利です。

[34.1 Overview | 34. Run-As Authentication Replacement](http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/#runas-overview)

[こっちのページ](https://dzone.com/articles/spring-security-run-example)だと、アプリのバックエンドでちょっと特殊な権限が必要になるときに、その特殊な権限を常にユーザに付与するわけにはいかない場合に、一時的に付与したいときに使えるとか説明されている。

<del class="small">ただ、それは権限の割り振りの設計が間違ってね？　という気がしなくもない。</del>

まぁ、知っておいたら何かのときに使える日が来るかもしれない。


# RunAsImplAuthenticationProvider の価値は？
## RunAsImplAuthenticationProvider がやること
`RunAsImplAuthenticationProvider` は `Authentication` オブジェクトの実体が `RunAsUserToken` の場合に認証処理をサポートする。

この `RunAsUserToken` は `RunAsManagerImpl` が生成する `Authentication` オブジェクトで、元の `Authentication` が持っていた情報に `RUN_AS_` で指定した権限が追加された `Authentication` オブジェクトとなっている。

この `RunAsUserToken` には、 `RunAsManagerImpl` を生成するときに指定した `key` が設定されている。

```xml:applicationContext.xml
    <bean id="runAsManager"
          class="org.springframework.security.access.intercept.RunAsManagerImpl">
        <property name="key" value="foo" /> ★これ
    </bean>
```

この `key` は `RunAsImplAuthenticationProvider` にも設定している。

```xml:applicationContext.xml
    <bean id="runAsAuthenticationProvider"
          class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
        <property name="key" value="foo" /> ★同じやつを設定している
    </bean>
```

`RunAsImplAuthenticationProvider` は、 `RunAsUserToken` に設定された `key` と、自分自身に設定された `key` を比較し、もし異なる場合は `BadCredentialsException` をスローするようになっている。

## いつ呼ばれる？
自分が確認した限りだと、普通に使っているだけだと `RunAsImplAuthenticationProvider` の処理が実行されることはない。

次の条件が満たされたときに実行されることは確認できた。

1. `MethodSecurityInterceptor` の `alwaysReauthenticate` が `true` になっている
2. `ProviderManager` の `eraseCredentialsAfterAuthentication` が `false` になっている（Form ログインが有効の場合）
3. Run-As で権限を書き換えているメソッドの中で、別のメソッドセキュリティの処理対象となるメソッドが呼ばれた

1 は、これが `true` になっていると `MethodSecurityInterceptor` が実行されるときに毎回 `AuthenticationManager` の認証処理が呼ばれるようになる。逆に `false` だと認証処理が呼ばれないので、 `RunAsImplAuthenticationProvider` の処理も呼ばれなくなる（デフォルトは `false`）。

2 は、これが `false` になっていないと Form ログインした時点でパスワードが `Authentication` オブジェクトから削除されてしまう。その状態で `MethodSecurityInterceptor` での `AuthenticationManager` の認証処理が実行されると、パスワードが取得できずに認証エラーになってしまう。

3 は、 `RunAsImplAuthenticationProvider` の処理が実行されるのが `Authentication` オブジェクトの実体が `RunAsUserToken` の場合のみなので、 Run-As が実行された後に呼ばれたメソッドだけが `RunAsImplAuthenticationProvider` の処理対象になることを意味している。

こんな設定にわざわざすることってあるのだろうか？

## 意味はある？
`RunAsImplAuthenticationProvider` は、 `key` の比較だけを行っているが、このチェックにはどういう意味があるのだろうか？

リファレンスでは、悪意あるコードがどうのこうのいう文章があったが、英語力がなくて何言っているのか分からず。。。

> To ensure malicious code does not create a RunAsUserToken and present it for guaranteed acceptance by the RunAsImplAuthenticationProvider, the hash of a key is stored in all generated tokens. The RunAsManagerImpl and RunAsImplAuthenticationProvider is created in the bean context with the same key:

http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/#runas-config

`RunAsUserToken` を攻撃者が偽造できることがあるということだろうか？
そんなことできる時点で、任意のコードが実行できてしまっている気がするが、どうなのだろう。。。

## 結論
わからん。

でも自分の気付いていないところで実は重要なチェックの働きをしているかもしれないので、念のために設定はしておいたほうがいいのかもしれない。

# もう少しスマートにする
## 問題点
```java
    @Secured({"ROLE_USER", "RUN_AS_HOGE", "RUN_AS_FUGA"})
    public void secured() {
        this.printAuthorities("secured");
    }
```

- 権限の指定（`ROLE_USER`）と Run-As の設定（`RUN_AS_FUGA`）が１つの配列上で指定されていて、分かりにくい
- 名前が `RUN_AS_` でないといけなかったり、その後付与される権限が `ROLE_` が固定でついたりして自由度が低い

[こちらの記事](https://dzone.com/articles/spring-security-run-example) を参考に、もうちょっとスマートに使えるようにする。

## 実装
```java:RunAs.java
package sample.spring.security.runas;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RunAs {
    String[] value();
}
```

- Run-As で追加する権限を定義するための専用のアノテーションを自作する

```java:MyRunAsManagerImpl.java
package sample.spring.security.runas;

import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.intercept.RunAsUserToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class MyRunAsManagerImpl extends RunAsManagerImpl {
    private static final Authentication NO_REPLACE = null;

    @Override
    public Authentication buildRunAs(Authentication authentication, Object secureObject, Collection<ConfigAttribute> attributes) {
        if (!this.supports(secureObject)) {
            return NO_REPLACE;
        }

        String[] runAsAuthorities = this.getRunAsAuthorities(secureObject);

        return new RunAsUserToken(
            this.getKey(),
            authentication.getPrincipal(),
            authentication.getCredentials(),
            this.createNewAuthorities(authentication, runAsAuthorities),
            authentication.getClass()
        );
    }
    
    private boolean supports(Object secureObject) {
        return (secureObject instanceof ReflectiveMethodInvocation)
                && ((ReflectiveMethodInvocation) secureObject).getMethod().isAnnotationPresent(RunAs.class);
    }
    
    private String[] getRunAsAuthorities(Object secureObject) {
        ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) secureObject;
        Method method = invocation.getMethod();
        RunAs runAs = method.getAnnotation(RunAs.class);
        return runAs.value();
    }
    
    private List<GrantedAuthority> createNewAuthorities(Authentication authentication, String[] runAsAuthorities) {
        List<GrantedAuthority> newAuthorities = new ArrayList<>(authentication.getAuthorities());
        
        for (String runAsAuthority : runAsAuthorities) {
            newAuthorities.add(new SimpleGrantedAuthority(runAsAuthority));
        }
        
        return newAuthorities;
    }
}
```

- デフォルト実装の `RunAsManagerImpl` を継承し、 `buildRunAs()` メソッドをオーバーライドする
- セキュアオブジェクトが `ReflectiveMethodInvocation` の場合で、かつ `@RunAs` でメソッドがアノテートされている場合にかぎり、処理を行うようにする
    - 権限の置き換えを行わない場合は、 `null` を `return` すればいい
- メソッドが `@RunAs` でアノテートされている場合は、 `value` を取得して新しい権限を追加した `RunAsUserToken` インスタンスを取得して `return` する


**namespace**

```xml:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       ...>

    <bean class="sample.spring.security.service.MyRunAsService" />

    <bean id="runAsManager"
          class="sample.spring.security.runas.MyRunAsManagerImpl">
        <property name="key" value="foo" />
    </bean>

    <bean id="runAsAuthenticationProvider"
          class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
        <property name="key" value="foo" />
    </bean>
    
    <sec:global-method-security pre-post-annotations="enabled" run-as-manager-ref="runAsManager" />
    
    <sec:http>
        ...
    </sec:http>

    <sec:authentication-manager>
        ...
        <sec:authentication-provider ref="runAsAuthenticationProvider" />
    </sec:authentication-manager>
</beans>
```

- `RunAsManager` の実装クラスを `MyRunAsManagerImpl` に変更
- `<global-method-security>` の `secured-annotations` を除去し、代わりに `pre-post-annotations` を有効に

**Java Configuration**

```java:MyGlobalMethodSecurityConfig.java
package sample.spring.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import sample.spring.security.runas.MyRunAsManagerImpl;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MyGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    
    public static final String RUN_AS_KEY = "foo";
    
    @Override
    protected RunAsManager runAsManager() {
        RunAsManagerImpl runAsManager = new MyRunAsManagerImpl();
        runAsManager.setKey(RUN_AS_KEY);
        return runAsManager;
    }
}
```

- namespace のほうと同じ変更を加える

```java:MyRunAsService.java
package sample.spring.security.service;

import org.springframework.security.access.prepost.PreAuthorize;
import sample.spring.security.runas.RunAs;
...

public class MyRunAsService {

    @PreAuthorize("hasRole('ROLE_USER')")
    @RunAs({"HOGE", "FUGA"})
    public void secured() {
        this.printAuthorities("secured");
    }
    
    ...
}
```

- `@Secured` の代わりに `@PreAuthorize` と `@RunAs` でメソッドをアノテートする


## 動作確認
`/run-as/secured` にアクセス

```text:サーバーコンソール出力
[メソッド呼び出し前]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[secured]
Authentication.class = class org.springframework.security.access.intercept.RunAsUserToken
ROLE_USER
HOGE
FUGA

[メソッド呼び出し後]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER
```

`/run-as/nonSecured` にアクセス

```text:サーバーコンソール出力
[メソッド呼び出し前]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[nonSecured]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER

[メソッド呼び出し後]
Authentication.class = class org.springframework.security.authentication.UsernamePasswordAuthenticationToken
ROLE_USER
```


# 参考
- [Spring Security Reference](http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/)
- [TERASOLUNA Server Framework for Java (5.x) Development Guideline — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.3.0.RELEASE documentation](http://terasolunaorg.github.io/guideline/5.3.0.RELEASE/ja/)
- [Spring Security Run-As example using annotations and namespace configuration - DZone DevOps](https://dzone.com/articles/spring-security-run-example)
- [Spring Security – Run-As Authentication | Baeldung](http://www.baeldung.com/spring-security-run-as-auth)
- [That Java Thing: Spring Security Run-As example using annotations and namespace configuration](http://thatjavathing.blogspot.jp/2014/07/spring-security-run-as-example-using.html)