コンテキストの切り替えについて

実行コンテキストは、セッションへの接続、またはモジュールの実行 (呼び出し) を行ったユーザーまたはログインによって決まります。実行コンテキストにより、ステートメントまたはアクションを実行する権限と照合される ID が作成されます。SQL Server では、EXECUTE AS ステートメントを実行したり、モジュールで EXECUTE AS 句を指定することにより、実行コンテキストを別のユーザーまたはログインに切り替えることができます。コンテキストが切り替えられると、SQL Server では、EXECUTE AS ステートメントまたはそのモジュールを呼び出したユーザーではなく、切り替えられたアカウントのログインとユーザーに対して権限が確認されます。コンテキスト切り替え後の残りのセッションまたはモジュールの実行中、あるいは切り替えが明示的に元に戻されるまでは、データベース ユーザーまたは SQL Server ログインの権限が借用されます。実行コンテキストの詳細については、「実行コンテキストについて」を参照してください。

明示的なコンテキストの切り替え

EXECUTE AS ステートメントでユーザー名またはログイン名を指定することで、セッションまたはモジュールの実行コンテキストを明示的に変更できます。次のいずれかのイベントが発生するまで、権限の借用は有効なままです。

  • セッションが削除された。

  • コンテキストが別のログインまたはユーザーに切り替えられた。

  • コンテキストが前の実行コンテキストに戻された。

明示的に別のユーザーの権限を借用するために EXECUTE AS を使用することは、以前のバージョンの SQL Server の SETUSER に似ています。詳細については、「EXECUTE AS と SETUSER」を参照してください。

サーバー レベルのコンテキストの明示的な切り替え

サーバー レベルで実行コンテキストを切り替えるには、EXECUTE AS LOGIN = 'login_name' ステートメントを使用します。ログイン名は sys.server_principals にプリンシパルとして表示される必要があります。また、ステートメントの呼び出し元は、指定したログイン名に対する IMPERSONATE 権限を所持する必要があります。

実行コンテキストがサーバー レベルにあるときの権限借用のスコープを次に示します。

  • login_name のログイン トークンは、SQL Server のインスタンスによって認証され、そのインスタンス全体で有効になります。

  • login_name のサーバー レベルの権限とロールのメンバシップが受け入れられます。

以前のコンテキストに戻すには、REVERT ステートメントを使用します。REVERT ステートメントの呼び出し側は、権限の借用が行われたのと同じデータベース上に存在する必要があります。

次の例では、Adventure Works Cycles のネットワーク管理者 Peter Connelly が、新しい従業員 Jinghao Liuhas 用に、SQL Server のログイン アカウントを作成します。Peter の SQL Server ログインには、SQL Server ログインの作成に必要なサーバー レベルの権限が与えられていません。しかし、必要なサーバー レベルの権限を持つ SQL Server ログイン、adventure-works\dan1 に対する IMPERSONATE 権限が与えられています。Peter が SQL Server に接続すると、Peter の SQL Server ログインからセッションの実行コンテキストが派生します。Peter は、SQL Server ログインを作成するために、一時的に adventure-works\dan1 の実行コンテキストを借用します。その後、ログインを作成します。最後に、Peter は借用した権限を解放します。

-- Switch execution context to the adventure-works\dan1 login account.
EXECUTE AS LOGIN = 'adventure-works\dan1';
-- Create the new login account.
CREATE LOGIN Jinghao1 WITH PASSWORD = '3KHJ6dhx(0xVYsdf';
-- Revert to the previous execution context.
REVERT;

-- Switch execution context to the adventure-works\dan1 login account.
EXECUTE AS LOGIN = 'adventure-works\dan1';
-- Create the new login account.
CREATE LOGIN Jinghao1 WITH PASSWORD = '3KHJ6dhx(0xVYsdf';
-- Revert to the previous execution context.
REVERT;

データベース レベルのコンテキストの明示的な切り替え

データベース レベルでコンテキストを切り替えるには、EXECUTE AS USER = 'user_name' ステートメントを使用します。ユーザー名は sys.database_principals にプリンシパルとして存在している必要があります。また、ステートメントの呼び出し元では、指定したユーザー名に対する IMPERSONATE 権限を所持する必要があります。

実行コンテキストがデータベース レベルにあるときの権限借用のスコープを次に示します。

  • SQL Server のインスタンスによって user_name のユーザー トークンが認証され、現在のデータベースで有効になります。ユーザーの権限借用を現在のデータベースのスコープ外に拡張する方法の詳細については、「EXECUTE AS の使用によるデータベースの権限借用の拡張」を参照してください。

  • 現在のデータベースに対する user_name のデータベース レベルの権限とロールのメンバシップが受け入れられます。ユーザー トークンまたはロールのメンバシップにより、ID に明示的に許可されたサーバー レベルの権限は受け入れられません。

以前のコンテキストに戻すには、REVERT ステートメントを使用します。REVERT ステートメントの呼び出し側は、権限の借用が行われたのと同じデータベース上に存在する必要があります。

次の例では、Adventure Works Cycles のデータベース管理者 François Ajenstat が、AdventureWorksDW データベースに対して DBCC CHECKDB ステートメントを実行する際に、これを行うデータベース レベルの権限を持っていない場合を示します。しかし、必要な権限を所持するアカウントである、ユーザー dan1 に対する IMPERSONATE 権限を所持しています。

François が AdventureWorksDW データベースに接続するときに、実行コンテキストがユーザー セキュリティ トークンにマップされます。François のユーザー トークンのプライマリ プリンシパルとセカンダリ プリンシパルに対して、ステートメントを実行する権限が確認されます。François には DBCC CHECKDB ステートメントを実行するために必要な権限がないので、次のステートメントを実行します。

-- EXECUTE AS USER = 'dan1';
-- Create a table in dan1's default schema
CREATE TABLE t_NewTable( data nvarchar(100) );
go
-- Revert to the previous execution context.
REVERT
go;

-- EXECUTE AS USER = 'dan1';
-- Create a table in dan1's default schema
CREATE TABLE t_NewTable( data nvarchar(100) );
go
-- Revert to the previous execution context.
REVERT
go;

コンテキストの暗黙の切り替え

ストアド プロシージャ、トリガ、キュー、ユーザー定義関数などのモジュールの場合、モジュール定義の EXECUTE AS 句にユーザー名またはログイン名を指定することで、実行コンテキストを暗黙的に変更できます。

モジュールが実行されているコンテキストを指定することにより、モジュールから参照されるオブジェクトの権限を検証するために SQL Server が使用するユーザー アカウントを制御できます。これにより、ユーザー定義モジュールとこれらのモジュールによって参照されるオブジェクトとの間に存在するオブジェクト チェーン全体の柔軟性が増し、権限の管理が容易になります。ユーザーに付与する必要のある権限は、モジュール自体に対するもののみで、参照されるオブジェクトに対する明示的な権限の許可は必要ありません。モジュールによってアクセスされるオブジェクトに対する権限が必要なのは、そのモジュールで権限が借用されているユーザーだけです。

権限借用のレベルは、権限借用が定義されるモジュールの種類によって決まります。

サーバー レベルの権限借用は、次のものに定義できます。

  • DDL トリガ

サーバー レベルの権限借用のスコープは、前述の「サーバー レベルのコンテキストの明示的な切り替え」で定義したものと同じです。

データベース レベルの権限借用は、次のものに定義できます。

  • DML トリガ

  • キュー

  • ストアド プロシージャ

  • ユーザー定義関数

  • データベース レベルの権限借用のスコープは、前述の「データベース レベルのコンテキストの明示的な切り替え」で定義したものと同じです。

  • コンテキストの暗黙の切り替えの詳細については、「モジュールでの EXECUTE AS の使用」を参照してください。

次の例では、Mary がテーブル MyTable の所有者とします。Mary はユーザー Scott がテーブルの切り捨てを実行できるようにしようとしていますが、Scott にはテーブルに直接アクセスできる権限がありません。そのため、Mary は、ストアド プロシージャ dbo.usp_TruncateMyTable を作成し、Scott にこのプロシージャの EXECUTE 権限を許可します。Scott がこのストアド プロシージャを実行すると、データベース エンジンでは Mary 自身がストアド プロシージャを実行したかのように、テーブルの切り捨てを行うための権限が確認されます。Mary はテーブルの所有者なので、Scott がテーブル自体に直接アクセスできる権限を所持していなくてもステートメントは成功します。

CREATE PROCEDURE dbo.usp_TruncateMyTable
WITH EXECUTE AS SELF
AS TRUNCATE TABLE MyDB..MyTable;

CREATE PROCEDURE dbo.usp_TruncateMyTable
WITH EXECUTE AS SELF
AS TRUNCATE TABLE MyDB..MyTable;