Explain About CURSORS in Oracle PL/SQL

Oracle PL/SQL Cursor



Introduction

Cursor is a temporary memory area (context area) where Oracle executes SQL statements. Oracle associates every SELECT statement with a cursor to hold the query information in this context area.

Types of Cursor

There are two types of cursors - implicit and explicit cursor.
Implicit cursor: Oracle automatically (implicit) controls or processes the information of SQL statement executed. In this process, the user is unaware of implicit cursor. Oracle automatically performs the OPEN, FETCH, and CLOSE operations.
Explicit cursor: Explicit cursor is used for the query that returns more than one row of data. These cursors are explicitly declared in the DECLARE section of the PL/SQL block. This declaration allows to sequentially process each row of data as the cursor returns it. In explicit cursor DECLARE,OPEN,FETCH,and CLOSE operations are done by the programmer.
The process of working with an explicit cursor:
  • Declare: The cursor is initialised into temporary memory area.
  • Open: The cursor is opened which is declared, and the temporary memory area is allotted.
  • Fetch: Cursor which is declared and opened can now retrieve rows from data.
  • Close: The CLOSE statement disables the cursor, and releases the temporary memory area.

Cursor Attributes

These attributes return useful information about the execution of a SQL statement. Cursor attributes can be used in procedural statements but not in SQL statements.
CURSOR ATTRIBUTE SYNTAX DESCRIPTION
%NOTFOUND
cursor_name%NOTFOUND
%NOTFOUND returns TRUE if last fetch did not return a row, Else FALSE if last fetch returns row.    
%FOUND
cursor_name%FOUND
%FOUND returns TRUE if the cursor is open, fetches the row till the last fetch. FALSE if last fetch did not return any row.
%ROWCOUNT
cursor_name%ROWCOUNT
%ROWCOUNT keeps track of fetched rows from cursor until it is closed.
%ISOPEN
cursor_name%ISOPEN
%ISOPEN returns TRUE if its cursor or cursor variable is open, otherwise, %ISOPEN returns FALSE.
The general syntax for creating a cursor is as follows :
CURSOR cursor_name IS select_statement;
  • cursor_name : name for the cursor
  • select_statement : select query which returns multiple rows
As we have gone through an introductory part , let's start exploring cursor with examples to understand more in depth. NOTE : In programming language, standardisation is the most important part. When you declare a cursor in declaration part, always start with initial c_cursor_name, it will always be clear that name refers to cursor.
Before we start with Explicit cursor, let us understand...

Record Types

Record is composite data structure, it is group of data items similar to the row of database table, each item with its own name and datatype. Assume the record is a variable which holds a table row or some columns of a table. If you want to learn more about RECORD, you can refer to PL/SQL User's Guide and Reference chapter 5.
PL/SQL supports only three types of records - table based, cursor based and programmer defined.
  • A table based record is one whose entire structure is similar to columns of a table.
  • A cursor based record is one whose structure is similar to items (elements) of a pre-defined cursor.
  • A cursor and record datatype created in declaration part of PL/SQL Block having the same variables with same datatype in the same order is called programmer defined record.
NOTE: To create a table based and cursor based record, always prefer to use %ROWTYPE attribute. The %ROWTYPE attribute provides a record type that represents a row in a database table. The record can store an entire row of data selected from the table or fetched from a cursor or cursor variable. To learn more about %ROWTYPE, refer to PL/SQL User's Guide and Reference chapter 2.

Example 1. Table based record

DECLARE
 vr_emp employees%ROWTYPE;
 /* variable vr_emp is a record type existing database table employees.
    record vr_emp has a similar structure to row of the employees table.*/ 
BEGIN
 SELECT * 
 INTO vr_emp  -- INTO clause always notifies only single row can be fetch
 FROM employees
 WHERE employee_id = 100;
 /* to display each element of record,reference each attribute of record with dot notation*/
 DBMS_OUTPUT.PUT_LINE('Employee Details : '||vr_emp.employee_id
 ||' '||vr_emp.first_name||' '||vr_emp.last_name||' '||vr_emp.salary);
END;
Employee Details : 100 Steven King 24000

Example 2. Cursor based record

DECLARE
 CURSOR c_emp_detail IS 
   SELECT employee_id,first_name,last_name,salary
   FROM employees;
   rec_emp_detail c_emp_detail%ROWTYPE;
   /* A cursor based record is based on elements of pre-Defined cursor.
      A cursor based record can be only declared after its corresponding
      cursor, else an error occurs.*/
BEGIN
 OPEN c_emp_detail;
   LOOP
    FETCH c_emp_detail INTO rec_emp_detail;
    EXIT WHEN c_emp_detail%NOTFOUND; -- cursor attribute to exit when no rows found to fetch.
    DBMS_OUTPUT.PUT_LINE('Employees Details : '||' '||rec_emp_detail.employee_id
    ||' '||rec_emp_detail.first_name||' '||rec_emp_detail.last_name);
   END LOOP;
    DBMS_OUTPUT.PUT_LINE('Total number of rows : '||c_emp_detail%ROWCOUNT);
    -- cursor attribute to find the total number of rows executed.
 CLOSE c_emp_detail;
END;
Employees Details :  198 Donald OConnell
Employees Details :  199 Douglas Grant
Employees Details :  200 Jennifer Whalen

-----------------------------

Employees Details :  196 Alana Walsh
Employees Details :  197 Kevin Feeney
Total number of rows : 107

Example 3. Programmer defined record

DECLARE
 CURSOR c_emp_detail IS
 SELECT employee_id,first_name,last_name,salary
 FROM employees;
/*declaring a record datatype, with same datatype of tables of database using %TYPE attribute,
  with same order of corresponding cursor */
TYPE type_rectype IS RECORD
    (emp_id employees.employee_id%TYPE,
     f_name employees.first_name%TYPE,
     l_name employees.last_name%TYPE,
     s_salary employees.salary%TYPE
    );
 rec_type type_rectype; --variable of record datatype.

BEGIN
 OPEN c_emp_detail;
  LOOP
   FETCH c_emp_detail INTO rec_type; -- Fetches the cursor into record variable.
   EXIT WHEN c_emp_detail%NOTFOUND;
-- variable is part of each record datatype,so to reference it use dot notation in DBMS_OUTPUT.
    DBMS_OUTPUT.PUT_LINE('Employees Details : '||' '||rec_type.emp_id
    ||' '||rec_type.f_name||' '||rec_type.l_name||' '||rec_type.s_salary);        
  END LOOP; 
    DBMS_OUTPUT.PUT_LINE('Total number of Employees : '||c_emp_detail%ROWCOUNT);
 CLOSE c_emp_detail;
END;
Employees Details :  198 Donald OConnell 2600
Employees Details :  199 Douglas Grant 2600
Employees Details :  200 Jennifer Whalen 4400

-----------------------------

Employees Details :  196 Alana Walsh 3100
Employees Details :  197 Kevin Feeney 3000
Total number of Employees : 107

Cursors in Nested Loops

Before going through Example 4, please make sure you have a better understanding of Nested loop concept, because Cursors in Nested Loops concept is absolutely the same as Nested Loops. To learn more about Loops, refer to PL/SQL User's Guide and Reference chapter 4.

Example 4. Cursors in Nested Loops

DECLARE
 CURSOR c_dept IS 
  SELECT * 
  FROM departments
  WHERE manager_id IS NOT NULL
  ORDER BY department_name;
  r_dept c_dept%ROWTYPE;

-- Declaration of department cursor and record variable.
  
  CURSOR c_emp (c_dept_no departments.department_id%TYPE) IS
  SELECT *
  FROM employees
  WHERE department_id = c_dept_no;
  r_emp c_emp%ROWTYPE;

-- Declaration of employees cursor and record variable.
  
BEGIN
   OPEN c_dept;
   LOOP
     FETCH c_dept INTO r_dept;
      EXIT WHEN c_dept%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE('----------------------------------');
      DBMS_OUTPUT.PUT_LINE('Department Name : '||r_dept.department_name);
      DBMS_OUTPUT.PUT_LINE('----------------------------------');
          OPEN c_emp(r_dept.department_id);
           LOOP
            FETCH c_emp INTO r_emp;
             EXIT WHEN c_emp%NOTFOUND;
                DBMS_OUTPUT.PUT_LINE('Employees Details : '||r_emp.employee_id
   ||' '||r_emp.first_name||' '||r_emp.last_name||' '||r_emp.salary);
           END LOOP;
          CLOSE c_emp;  
   END LOOP;
   CLOSE c_dept;
END;
----------------------------------
Department Name : Accounting
----------------------------------
Employees Details : 205 Shelley Higgins 12000
Employees Details : 206 William Gietz 8300

-----------------------------

----------------------------------
Department Name : Shipping
----------------------------------
Employees Details : 198 Donald OConnell 2600
Employees Details : 199 Douglas Grant 2600

-----------------------------
The c_emp cursor specifies the parameter in c_dept_no. Each time cursor c_emp is called, it returns only the list of employees of which the department_id specified by the parameter (c_dept_no). In Example 4, if we segregate the individual cursor c_emp, it becomes a parameterised cursor.

Cursor For Loops

In Cursor for loops, the process of opening, fetching and closing is handled implicitly. This makes the programmer code and maintain the blocks easily.
In cursor for loop, before each iteration PL/SQL fetches into implicitly declared record.
The sequence of statements inside the loop is executed once for each row that satisfies the query.
When loop is left, the cursor is automatically closed.
The cursor is closed even if you use an EXIT or GOTO statement to leave the loop before all rows are fetched.

Example 5. Implicit cursor for loop

BEGIN
  FOR item IN(SELECT department_name,d.department_id,last_name,job_id,salary
              FROM departments d JOIN employees e
              ON e.department_id = d.department_id
              WHERE JOB_ID       = 'IT_PROG'
              AND salary         > 4800)
    LOOP
      DBMS_OUTPUT.PUT_LINE(item.last_name||' '||item.department_name
      ||' '||item.department_id||' '||item.job_id||' '||item.salary);
    END LOOP;
END;
Hunold IT 60 IT_PROG 9000
Ernst IT 60 IT_PROG 6000
If you need the same query to reference from different parts of the same procedure, you can declare a cursor with that specific query,and get the results using cursor for loop. For this, I am going to use the same select query from Example 5.

Example 6. Explicit cursor for loop

DECLARE
 CURSOR c_detail IS
  SELECT department_name,d.department_id,last_name,job_id,salary
              FROM departments d JOIN employees e
              ON e.department_id = d.department_id
              WHERE JOB_ID       = 'IT_PROG'
              AND salary         > 4800;
              
BEGIN
  FOR item IN c_detail
    LOOP
      DBMS_OUTPUT.PUT_LINE(item.last_name||' '||item.department_name
      ||' '||item.department_id||' '||item.job_id||' '||item.salary);
    END LOOP;
END;
Hunold IT 60 IT_PROG 9000
Ernst IT 60 IT_PROG 6000

Example 7. Nested Cursors Using Cursor FOR Loops

If you notice, example 4 and example 7 outputs are the same, the difference is example 7. We are using cursor for loop where record variable declares r_dept and r_emp , opening fetching and closing is done automatically by each loop iteration until all rows are fetched according to the specific query in cursor.
The variable v_dept_id is initialized to be the department_id of the current record of the c_dept cursor. The c_dept cursor ties in the c_emp cursor by means of this variable.
Thus, when the cursor c_emp is processed, it is retrieving employees who have the department_id of the current record for the c_dept cursor.
Each iteration of the c_dept cursor will execute the DBMS_OUTPUT only once. The DBMS_OUTPUT will be executed once for each iteration of the c_emp cursor loop, producing a line of output for each employee.
DECLARE
  v_dept_id departments.department_id%TYPE;
 CURSOR c_dept IS
  SELECT * 
  FROM departments
  WHERE manager_id IS NOT NULL
  ORDER BY department_name;
 CURSOR c_emp IS
  SELECT * 
  FROM employees
  WHERE department_id = v_dept_id;
  
BEGIN
    FOR r_dept IN c_dept
    LOOP
      v_dept_id := r_dept.department_id;
      DBMS_OUTPUT.PUT_LINE('----------------------------------');
      DBMS_OUTPUT.PUT_LINE('Department Name : '||r_dept.department_name);
      DBMS_OUTPUT.PUT_LINE('----------------------------------');
           FOR r_emp IN c_emp 
           LOOP
             DBMS_OUTPUT.PUT_LINE('Employee Name : '||r_emp.last_name);
           END LOOP;   
    END LOOP;
END;
----------------------------------
Department Name : Accounting
----------------------------------
Employee Name : Higgins
Employee Name : Gietz
----------------------------------

--------------------

----------------------------------
Department Name : Shipping
----------------------------------
Employee Name : OConnell
Employee Name : Grant

--------------------

Example 8. Using Parameters with Nested Cursors For Loops

CREATE OR REPLACE PROCEDURE print_emp_dept(v_lo_id IN locations.location_id%TYPE)
IS
  v_flag departments.department_id%TYPE;
   CURSOR c_locations IS
   SELECT * 
   FROM locations
   WHERE location_id = v_lo_id;  
     
   CURSOR c_departments(v_loc_id locations.location_id%TYPE) IS
    SELECT l.location_id,department_name,department_id
    FROM locations l JOIN departments d
    ON l.location_id = d.location_id
    WHERE l.location_id = v_loc_id
    AND d.manager_id IS NOT NULL;
    
   CURSOR c_employees (v_dept_id departments.department_id%TYPE,
                       v_loc_id locations.location_id%TYPE) IS
    SELECT d.department_id,employee_id,first_name,last_name,salary,job_id,city
    FROM locations l JOIN departments d
    ON   l.location_id = d.location_id  
    JOIN employees e
    ON  d.department_id = e.department_id
    WHERE d.department_id = v_dept_id
    AND l.location_id = v_loc_id;
BEGIN
     FOR r_location IN c_locations
     LOOP 
         DBMS_OUTPUT.PUT_LINE
         ('Location ID : '||r_location.location_id||
         ' Belong''s to '||r_location.city||' city');
         DBMS_OUTPUT.PUT_LINE('In city '||r_location.city||' '||'Departments are ');
           FOR r_department IN c_departments(r_location.location_id)           
            LOOP 
              DBMS_OUTPUT.PUT_LINE('-----------------------------------------');
              DBMS_OUTPUT.PUT_LINE('Department ID :
              '||r_department.department_id||' '||'Location ID : '||
     r_department.location_id||' '||
     'Department Name : '||r_department.department_name);
              DBMS_OUTPUT.PUT_LINE('-----------------------------------------');   
                 v_flag := r_department.department_id;
                 EXIT WHEN v_flag IS NULL;  
                 
                  FOR r_employee IN c_employees 
                  (r_department.department_id,r_location.location_id)
                  LOOP
                   DBMS_OUTPUT.PUT_LINE(r_employee.employee_id||' 
                   '||r_employee.first_name||' '||
                   r_employee.last_name||' work''s in city '||r_employee.city);
                  END LOOP; 
                 
            END LOOP;           
     END LOOP; 
     IF v_flag IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('Not Available');
     END IF;
END print_emp_dept;
Call the procedure:
CALL print_emp_dept(3000);

BEGIN
 print_emp_dept(1700);
END;
Location ID : 1400 Belong's to Southlake city
In city Southlake Departments are 
-----------------------------------------
Department ID :60 Location ID : 1400 Department Name : IT
-----------------------------------------
103 Alexander Hunold work's in city Southlake
104 Bruce Ernst work's in city Southlake
105 David Austin work's in city Southlake
106 Valli Pataballa work's in city Southlake
107 Diana Lorentz work's in city Southlake
The grandparent cursor, c_locations is declared. It is a collection of locations and takes parameter while call of procedure print_emp_dept with a location_id is available in database.
The parent cursor, c_departments is declared. It takes in the parameter of location_ID to generate a list of departments that belongs to parameter location_ID.
The child cursor, c_employees takes in two parameters, department_id and location_id. In this way, it generates a list of employees working with different departments but in the same location_id.
The grandparent cursor loop begins, and only the city name and location_id is displayed with DBMS_OUTPUT. The parent cursor loop begins. It takes the parameter of location_id from the grandparent cursor where department_id, location_id and department_name is displayed.
The child cursor loop begins. It takes in the parameter of department_id from the parent cursor and location_id from the grandparent cursor.The employee_id and employees name is displayed in which city they work because of the parameter which has been used from grandparent cursor.
In this complete process, the child cursor loop ends first, then parent cursor loop ends, then grandparent cursor loop ends.

Example 9. For UPDATE and WHERE CURRENT CLAUSE

The FOR UPDATE clause is only used in cursor, when update or delete statements are used for database tables. Normally, when programmer executes SELECT statement, there is no locking of rows. The main aim to use FOR UPDATE clause is to lock rows when performing update or delete statements inside the cursor, and restrict other users to perform any updation in particular database tables. Once the updation is done inside the cursor, then COMMIT or ROLLBACK placed inside the execution block releases the lock. Now FOR UPDATE clause with particular Column name i.e.. FOR UPDATE salary will only lock salary column according to select statement even if there is join condition, else FOR UPDATE clause will lock entire row of that particular table.
NOWAIT is an optional keyword, if the rows are already locked by another programmer, then control is immediately returned to programmer so that meanwhile he can do other work before trying again. If you omit the keyword, then the wait may be a long period of time.
The WHERE CURRENT OF clause can be used only if FOR UPDATE clause is used in cursor.
The WHERE current of clause only references the cursor which fetches the latest row.
The WHERE CURRENT OF CLAUSE is useful to eliminate the where condition in update clause.
First, I have created a demo table, because I don't want to change data in the actual table of database.
create table emp1 as select * from employees;
create table dept1 as select * from departments;
DECLARE
 CURSOR c_sal_update IS
   SELECT employee_id,first_name,last_name,job_id,department_name,e.department_id,salary
   FROM dept1 d , emp1 e
   WHERE e.department_id = 80
   FOR UPDATE OF salary NOWAIT;
   
   rec_sal c_sal_update%ROWTYPE;
   
BEGIN
   OPEN c_sal_update;   -- rows are locked.
     LOOP
       FETCH c_sal_update INTO rec_sal;      
       EXIT WHEN c_sal_update%NOTFOUND;
       
       IF rec_sal.job_id = 'SA_MAN' THEN
         UPDATE emp1 
          SET salary = rec_sal.salary + 1000
          WHERE CURRENT OF c_sal_update; 
       END IF;
     END LOOP;
     COMMIT;  -- rows are unlocked.
   CLOSE c_sal_update;
END;
OUTPUT
SELECT employee_id,first_name,last_name,job_id,department_id,salary
FROM emp1
WHERE job_id = 'SA_MAN'
AND department_id = 80;

EMPLOYEE_ID FIRST_NAME      LAST_NAME         JOB_ID     DEPARTMENT_ID   SALARY
----------- --------------- ----------------- ---------- ------------- --------
        145 John            Russell           SA_MAN                80    15000 
        146 Karen           Partners          SA_MAN                80    14500 
        147 Alberto         Errazuriz         SA_MAN                80    13000 
        148 Gerald          Cambrault         SA_MAN                80    12000 
        149 Eleni           Zlotkey           SA_MAN                80    11500 

Example 10. Cursor attributes with explicit cursor

DECLARE
  CURSOR c_high_sal IS
     SELECT *
     FROM (SELECT employee_id,first_name,last_name,salary
           FROM employees ORDER BY salary DESC)
     WHERE ROWNUM < 11;   
     
   high_sal c_high_sal%ROWTYPE;
   
BEGIN
   IF NOT c_high_sal%ISOPEN THEN
     DBMS_OUTPUT.PUT_LINE('Cursor is Closed');
   END IF;  

  OPEN c_high_sal; 
     IF c_high_sal%ISOPEN THEN
        DBMS_OUTPUT.PUT_LINE('Cursor is open');
     END IF;
       
     LOOP
       FETCH  c_high_sal INTO high_sal;  
         IF c_high_sal%FOUND THEN                
           DBMS_OUTPUT.PUT_LINE(high_sal.employee_id||' '||high_sal.first_name
           ||' '||high_sal.last_name||' '||high_sal.salary);
         ELSE   
            EXIT; -- the same as exit when c_high_sal%NOTFOUND;
         END IF;           
     END LOOP;
            DBMS_OUTPUT.PUT_LINE(' Number of rows fetched : '||c_high_sal%ROWCOUNT);
  
  CLOSE c_high_sal;
  
  IF NOT c_high_sal%ISOPEN THEN
     DBMS_OUTPUT.PUT_LINE('Cursor is closed ');
  END IF;     
END;
Cursor is Closed
Cursor is open
100 Steven King 24000
101 Neena Kochhar 17000
102 Lex De Haan 17000
145 John Russell 14000
146 Karen Partners 13500
201 Michael Hartstein 13000
205 Shelley Higgins 12000
108 Nancy Greenberg 12000
147 Alberto Errazuriz 12000
168 Lisa Ozer 11500
 Number of rows fetched : 10
Cursor is closed
The cursor declared in the preceding example executes highest salary paid employees. Using sub-query in cursor. declare high_sal with %ROWTYPE.
The cursor is not yet open, %ISOPEN attribute is used to see whether cursor is open with help of IF-THEN statement, where %ISOPEN turn TRUE.
Cursor is open, now to show with DBMS_OUTPUT, %ISOPEN is used with IF-THEN statement, where %ISOPEN turn TRUE.
Now loop start and cursor c_high_sal is fetched into variable high_sal, again %FOUND attribute is used with IF-THEN-ELSE statement to show the list of highest paid employees, where %FOUND attribute turns true till the last fetch of cursor and exits from the loop.
Once it is out of the loop, DBMS_OUTPUT fetches the last number of row of loop and shows the figure with %ROWCOUNT attribute. Cursor is closed.
After the cursor is closed, %ISOPEN is used with the help of IF-THEN statement to show the cursor is closed.

Example 11. Cursor attributes with Implicit cursor

DECLARE
 v_dept departments.department_id%TYPE := 270;
 v_dept_name departments.department_name%TYPE;
BEGIN

DELETE FROM dept1 WHERE department_id = v_dept;
 IF SQL%FOUND THEN
   INSERT INTO dept1 VALUES(270,'Personnel',200,1700);
 END IF;
  DBMS_OUTPUT.PUT_LINE('Number of rows inserted : '||SQL%ROWCOUNT);
  
  SELECT department_name INTO v_dept_name
  FROM dept1
  WHERE department_id = 270;
    DBMS_OUTPUT.PUT_LINE('Department Name : '||v_dept_name);    
END;
Number of rows inserted : 1
Department Name : Personnel
An implicit cursor can tell you how many rows were affected by an update, insert and delete with the help of %FOUND and %ROWCOUNT attribute.
We have already created a table named dept1 in the previous example. In the following example, variables v_dept and v_dept_name are reference by table departments, as we are working on table dept1,it will not give any error unless the structure or datatype is different from the other table, i.e., departments and dept1.
Deleting from dept1 table where department_id is 270.
Using SQL instead of cursor name as it is implicit cursor with no cursor name.
Use %FOUND attribute with IF-THEN statement to insert row in dept1 table with new department_name, i.e., Personnel. Once it is inserted to know how many rows were affected, use %ROWCOUNT in DBMS_OUTPUT.
In same execution block using v_dept_name, we are fetching new department name with select statement.
I have not placed any commit because I don't want to update any row so later I will rollback it.
To learn more about implicit cursor and its attributes, refer to PL/SQL User's Guide and Reference chapter 6.
NOTE: Between implicit and explicit cursor, the fastest is implicit cursor, because opening and closing of cursor and looping is automatically handled by Oracle. Cursor for loop is also an implicit cursor where opening and closing of cursor in done implicitly. But cursor should be used according to requirement because each type of cursor has its own advantages and disadvantages. To know more about this, you can refer to Steven Feuerstein's book PL-SQL Programming 5th edition.
The concepts like Refs cursor, cursor with bulk operations, cursor with packages and cursor with exception are not covered which is out of scope of this article. I may write my next article covering all these concepts and thank you for reading this article.

Formatting enums for user Defined Formatt

Formatting enums using CustomFormatters

C# enums are named constants, making code easier to write and read. But the enum names should not be written to the UI. This post shows two methods of formatting an enum to a string suitable for the UI.

A C# enum is simply a named constant: Let’s say you are working on a application where you need to represent the fundamental forces in some way (if you cannot remember what that is, don’t worry, this could be anything really – fruits, cars, countries). The four forces are represented with a number, from 1 to 4 - and the C# enum construct lets you attach a name to each number:
public enum Force : byte
{
    [Description("Gravity")]
    Gravity = 1,
    [Description("Electromagnetic force")]
    Electromagnetic = 2,
    [Description("Weak nuclear force")]
    Weak = 3,
    [Description("Strong nuclear force")]
    Strong = 4
}

Each enum pair is also given a description using the DescriptionAttribute (located in System.ComponentModel). I will return to this attribute later.
Now, if you want to output an enum name to the UI (e.g. the console or a Webpage), the simplest way is to do the following:
Force f = Force.Strong;
Console.WriteLine(String.Format("Force: {0}", f));

The String.Format method simply calls f.ToString(), and inserts the resulting string in the overall string. The result is as expected:
Force: Strong
But this solution should be avoided. The enum name is a coding “shortcut”, and should never be displayed on the UI. That is because special characters and spaces are not allowed in the enum names, and localization is not supported.

The means that if I would like to output Strong nuclear force instead of the enum name Strong, I would need another way. This could be accomplished but outputting the description instead of the name. This requires some coding, but can be done like this:
public static string GetDescription<T>(T value)
{
    DescriptionAttribute[] d = (DescriptionAttribute[])(typeof
    (T).GetField
   
(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute),
   
false));
    return d[0].Description;
}

This method takes an enum type and an enum value, and returns the DescriptionAttribute as a string:
Console.WriteLine(String.Format("Force: {0}", GetDescription<Force>(f)));
And the result is:
Force: Strong nuclear force

While this method is rather common, it is not a favorite of mine. The reason is, that the DescriptionAttribute is not a suitable place to put UI strings because it can only accessed through reflection. The method is not very flexible, say you need to format the same enum in two different ways in different parts of you application, since you cannot have more than one description to an enum pair.
The best way is, in my opinion, to use a CustomFormatter. This needs a little explanation: Formatting in C# is done by objects that implement the IFormatProvider interface. This interface contains only one method, object GetFormat(Type formatType). When a method employs a IFormatProvider, it will ask the GetFormat method for the specific formatter needed. If the method needs to format some numbers it will call GetFormat and ask for a NumberFormatInfo formatter. This object contains all the methods needed to format numbers.
On a side note, notice that the most common IFormatProvider is CultureInfos: They got a GetFormat method, and asked for a NumberFormatInfo object, it will return a culture specific NumberFormatInfo object. The CultureInfo object contains other formatters as well, formatters for formatting Dates, formatters for comparing strings and so on. The IFormatProvider is a factory, that will construct a whole range of different formatters when asked to.
Well, back to the enums: When the String.Format method is called with a IFormatProvider, it will first try to retrieve a type of formatter, that implementing the ICustomFormatter interface. It will then use this CustomFormatter to format each of the parameters.
The ICustomFormatter interface contains a single method: string Format(string format, object o, IFormatProvider formatProvider). This method is called by String.Format for each parameter. The first parameter takes a format string. This string can be added in the String.Format method, like:
String.Format(myFormatProvider, "Force: {0:R}", f);
Then the string “R” is passed to the CustomFormatter. This can be used to support different kinds of formatting with the same CustomFormatter. The object o is the object to be formatted, and the formatProvider is the formatProvider that actually constructed this CustomFormatter.
Now, let’s create a CustomFormatter that will format the Force enum:

public class ForceCustomFormatter : ICustomFormatter
{
    public string Format(string format, object o, IFormatProvider
    formatProvider)
    {
        if (!o.GetType().Equals(typeof(Force)))
        {
            return o.ToString();
        }
        else
        {
            Force force = (Force)o;
            switch (force)
            {
                case Force.Electromagnetic:
                     return "Electromagnetic force";
                case Force.Strong:
                     return "Strong nuclear force";
                case Force.Weak:
                     return "Weak nuclear force";
                default:
                     return force.ToString();
            }
        }
    }
}

The formatter is simple: If the supplied object is anything but a Force enum, the formatter will simply call the objects ToString method. Force objects is on the other hand formatted using a switch statement.
Last, we will need a provider that will construct a ForceCustomFormatter:
public class ForceFormatProvider : IFormatProvider
{
    public object GetFormat(Type formatType)
    {
         return (formatType == typeof(ICustomFormatter)) ? new
        
ForceCustomFormatter () : null;
    }
}

This method constructs a ForceCustomFormatter is asked for a ICustomFormatter.
Let’s summarize: The call
Console.WriteLine(String.Format(new ForceFormatProvider(), "Force: {0}", f));
Needs to format the Force enum f. It will call the ForceFormatProvider to retrieve a CustomFormatter. Then it will pass the parameters on at a time to the CustomFormatter, and use the resulting string. This is, in my opinion, the best way to format enum – and other objects as well. In reality, you want to make formatters that can format more than one object. You will also want to take a look at the part:

if (!o.GetType().Equals(typeof(Force)))
{
     return o.ToString();
}

This is the most basic formatting option, and if the object – like e.g. DateTime supports formatting with ToString(string format, IFormatProvider), you should revert to this method instead

Authorization In WCF-Based Services method based

Once you start adopting service-oriented principles for your distributed applications, the security challenges become slightly different. You suddenly realize that you are crossing a security boundary for every service call you make.
Typically—though not necessarily—there will be a network between the sender and the recipient of a service call. While authentication is usually handled automatically by the communication framework, you still have to come up with your own authorization strategy and infrastructure.
Windows Communication Foundation (WCF) provides powerful facilities for implementing authorization in services. You have the choice between an easy-to-use, role-based system as well as a more powerful, but more complex, claims-based API. The remainder of this article will compare both systems and show how to use them to implement robust service authorization.

Role-Based Authorization
The idea behind role-based authorization is that you associate a list of roles with a user. At run time, the service code queries the list to make security-related decisions. These roles can come from the Windows security system (where they are called groups) or from some custom store, such as a database.
The roles API in the Microsoft .NET Framework is based on two interfaces called IIdentity (identity information) and IPrincipal (role information). An IIdentity-derived class holds information such as the name of the user, whether he is authenticated, and how he was authenticated.
An IPrincipal-derived class must implement a single method called IsInRole where you can pass in a role name and get a Boolean response. In addition, the principal has a reference to the identity class it wraps.
The .NET Framework ships with several implementations of theses interfaces. WindowsIdentity and WindowsPrincipal wrap details about a Windows user. GenericIdentity and Generic­Principal can be used to represent a custom, authenticated user.
There is also a location where you can store a principal to associate it with the currently executing thread in your application (for example, a WCF operation request). This is the CurrentPrincipal thread static property on the System.Threading.Thread class. The typical course of events is that one part of an application populates Thread.CurrentPrincipal so that another part of the application can reach into this property to grab the IPrincipal implementation stored there. Then the IsInRole method can be called on that class to query the role list of the current user to ensure that the caller is authorized for the operation.
This is exactly how it works in WCF. Based on the configured authentication and credential type, WCF creates a corresponding IIdentity implementation—a WindowsIdentity for Windows authentication, a GenericIdentity for most other cases. Then, based on the configuration of the WCF service behavior, ServiceAuthorization, an IPrincipal implementation is created that wraps this identity and provides role information. This IPrincipal is then set on Thread.CurrentPrincipal so that it is accessible to the service operations.
Aside from programmatically calling IsInRole to perform role-based security checks, there is also an attribute called Principal­PermissionAttribute that allows you to annotate your service operations with role requirements. PrincipalPermission­Attribute will signal a negative authorization outcome to your client by throwing a SecurityException prior to executing the service operation. WCF will catch this exception and turn it into an Access Denied fault message that is returned. The WCF client plumbing will turn this special fault into a .NET exception of type SecurityAccess­DeniedException. Figure 1 shows the various ways to do a role check and perform error handling.

Service
class Service : IService { // only 'users' role member can call this method [PrincipalPermission(SecurityAction.Demand, Role = 'users')] public string[] GetRoles(string username) { // only administrators can retrieve the role information for other users if (ServiceSecurityContext.Current.PrimaryIdentity.Name != username) { if (Thread.CurrentPrincipal.IsInRole('administrators')) { ... } else { // access denied throw new SecurityException(); } } } }

Client
var factory = new ChannelFactory<IService>('*'); factory.Credentials.UserName.UserName = 'bob'; factory.Credentials.UserName.Password = 'bob'; var proxy = factory.CreateChannel(); try { Console.WriteLine('\nBob: roles for Bob --'); proxy.GetRoles('bob').ToList().ForEach(i => Console.WriteLine(i)); Console.WriteLine('\nBob: roles for Alice --'); proxy.GetRoles('alice').ToList().ForEach(i => Console.WriteLine(i)); } catch (SecurityAccessDeniedException) { Console.WriteLine('Access Denied\n'); }
The ServiceAuthorization service behavior controls the creation of the IPrincipal instance to be associated with the request thread. By default, WCF assumes Windows authentication and tries to populate Thread.CurrentPrincipal with a WindowsPrincipal.
When your clients are not Windows users, you have the choice between getting roles from an ASP.NET role provider or implementing a custom authorization policy in order to get the roles from a custom database. Another alternative is to implement a custom IPrincipal type and then take complete control over the IsInRole implementation.

ASP.NET Role Provider
WCF can use an ASP.NET role provider to retrieve roles for a user. You can either use one of the built-in providers (for SQL Server or Microsoft Authorization Manager) or write one of your own by deriving from System.Web.Security.RoleProvider.
To make the connection to the role provider, WCF attaches a RoleProviderPrincipal to the executing thread that forwards all calls to IsInRole to the role provider's IsUserInRole method. This method takes the user name and role in question and returns true if the user is a member of that role and false if not.
Figure 2 shows a sample custom role provider along with the necessary configuration entries. WCF will call the role provider for every role check that occurs in your service. If you have a lot of role checks, it would be beneficial to implement some sort of caching strategy to avoid excessive round-trips to the role store.

Role Provider
class CustomRoleProvider : RoleProvider { public override string[] GetRolesForUser(string username) { if (username == 'administrator') { return new string[] { 'administrators', 'users' }; } else { return new string[] { 'sales', 'marketing', 'users' }; } } public override bool IsUserInRole(string username, string roleName) { return GetRolesForUser(username).Contains(roleName); } ... }

Configuration
<behaviors> <serviceBehaviors> <behavior name='security'> <serviceAuthorization principalPermissionMode='UseAspNetRoles' roleProviderName='CustomProvider' </serviceAuthorization> </behavior> </serviceBehaviors> </behaviors> <system.web> <roleManager enabled='true' defaultProvider='CustomProvider'> <providers> <add name='CustomProvider' type='Service.CustomRoleProvider, Service' /> </providers> </roleManager> </system.web>
Customizations like caching could be implemented in the role provider itself or via a custom IPrincipal implementation. That's the next option we will explore.

Custom Principal
Another option is to supply your custom IPrincipal implementation to WCF. This gives you the chance to implicitly run code after the authentication stage of each request. For this you have to create your own custom principal and return it to the WCF plumbing. The custom principal will then be available from Thread.Cur­rentPrincipal to the service code. Custom principals allow full customization of role-based security and expose specialized security logic for the service developer to use.
Writing a custom principal is straightforward. Simply implement the IPrincipal interface and add your own custom functionality. To integrate the principal with WCF, you have to set the Principal­Per­missionMode attribute in the ServiceAuthorization element to "custom" and provide an authorization policy that is responsible for creating the principal and giving it back to WCF.
An authorization policy is simply a class that implements the System.IdentityModel.Policy.IAuthorizationPolicy interface. Implementations of this interface must employ a method called Evaluate, which gets called on every request. Here you can reach into the WCF service security context and set the custom principal. Figure 3 shows a custom principal as well as the authorization policy and its corresponding configuration entries.

Principal
class CustomPrincipal : IPrincipal { IIdentity _identity; string[] _roles; Cache _cache = HttpRuntime.Cache; public CustomPrincipal(IIdentity identity) { _identity = identity; } // helper method for easy access (without casting) public static CustomPrincipal Current { get { return Thread.CurrentPrincipal as CustomPrincipal; } } public IIdentity Identity { get { return _identity; } } // return all roles (custom property) public string[] Roles { get { EnsureRoles(); return _roles; } } // IPrincipal role check public bool IsInRole(string role) { EnsureRoles(); return _roles.Contains(role); } // cache roles for subsequent requests protected virtual void EnsureRoles() { // caching logic omitted – see the sample download } }

Authorization Policy
class AuthorizationPolicy : IAuthorizationPolicy { // called after the authentication stage public bool Evaluate(EvaluationContext evaluationContext, ref object state) { // get the authenticated client identity from the evaluation context IIdentity client = GetClientIdentity(evaluationContext); // set the custom principal evaluationContext.Properties['Principal'] = new CustomPrincipal(client); return true; } // rest omitted }

Configuration
<behaviors> <serviceBehaviors> <behavior name='security'> <serviceAuthorization principalPermissionMode='Custom'> <authorizationPolicies> <add policyType='Service.AuthorizationPolicy, Service' /> </authorizationPolicies> </serviceAuthorization> </behavior> </serviceBehaviors> </behaviors>

Centralizing Authorization Logic
So far you have seen how you can access the role information that is provided by the WCF security system from within your service operations. Sometimes, however, it is also useful to have centralized logic that can inspect every incoming request and make authorization decisions without having to spread that logic over all your service operations. Enter the service authorization manager.
The service authorization manager is a class that derives from System.ServiceModel.ServiceAuthorizationManager. You can override the CheckAccessCore method to run custom authorization code for each request. In CheckAccess, you have access to the current security context as well as the incoming message, including the headers. When you return false from CheckAccess, WCF will create the Access Denied fault message and send that back to the client. A return value of true will grant access to the service operation.
You can find the unique identifier of the operation that the client tries to call in the WS-Addressing action header. This value can be obtained from IncomingMessageHeader.Action property on the operation context that is passed into CheckAccess. The format of the action value is:
ServiceNamespace/ContractName/OperationName
For example, you might see something like this:
urn:msdnmag/ServiceContract/GetRoles
WCF passes in the complete request message as a ref parameter. This allows inspecting and even changing the message before it reaches the service operation (or gets bounced back because of a negative authorization outcome).
Be aware that messages in WCF are always read-once. That means you first have to create a copy of the message before you inspect the body. This can be done by creating a message buffer using the following code (you need to be careful with large or streamed messages):
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy( int.MaxValue);
Once you have created a copy of the message, you can use the standard APIs to get access to its content. In Figure 4, you can see a sample implementation of a service authorization manager that moves the authorization logic from the service operation to a central place.

Code
class AuthorizationManager : ServiceAuthorizationManager { public override bool CheckAccess( OperationContext operationContext, ref Message message) { base.CheckAccess(operationContext, ref message); string action = operationContext.IncomingMessageHeaders.Action; if (action == 'urn:msdnmag/IService/GetRoles') { // messags in WCF are always read-once // we create one copy to work with, and one copy for WCF MessageBuffer buffer = operationContext.RequestContext.RequestMessage. CreateBufferedCopy(int.MaxValue); message = buffer.CreateMessage(); // get the username value using XPath XPathNavigator nav = buffer.CreateNavigator(); StandardNamespaceManager nsm = new StandardNamespaceManager(nav.NameTable); nsm.AddNamespace('msdn', 'urn:msdnmag'); XPathNavigator node = nav.SelectSingleNode ('s:Envelope/s:Body/msdn:GetRoles/msdn:username', nsm); string parameter = node.InnerXml; // check authorization if (operationContext.ServiceSecurityContext.PrimaryIdentity.Name == parameter) { return true; } else { return (GetPrincipal(operationContext).IsInRole( 'administrators')); } } return true; } // rest omitted }

Configuration
<serviceAuthorization serviceAuthorizationManagerType='Service.AuthorizationManager, Service'>

Claims-Based Authorization
Once you reach a critical mass of services and complexity, role-based security may not be powerful or flexible enough. It doesn't take much for an enterprise scale, service-oriented application to become extremely complicated. Various clients using various client frameworks and credential types talk to various back-end services. These back-end services, in turn, call other services. Sometimes this is done in a trusted subsystem fashion where only the direct caller is authorized. Alternately, sometimes the original caller identity has to be forwarded throughout the call chain. The situation starts to get really complex as soon as external clients (such as partners or customers) need access to some of your internal services.
It quickly becomes apparent that, in a more complex system, the capabilities of IIdentity and IPrincipal may not be sufficient to model identity and authorization data. Role-based security is limited to binary decisions and does not allow arbitrary data to be associated with a subject. A technology-neutral format is needed that allows describing the identities of entities participating in your distributed system.
This is why the .NET Framework, starting in version 3.0, contains a new identity and access-control API that can handle these requirements with a claims-based approach. You can find this new API in the System.IdentityModel assembly and namespace. Furthermore, Microsoft just recently released a preview of its new identity framework code-named "Zermatt." This new framework builds upon the classes and concepts found in System.IdentityModel and makes it easier to build claims-based security into services and applications. It is important to note that System.IdentityModel as well as Zermatt are not bound in any way to WCF and can be used to claims enable any .NET application. It just happens that these APIs are deeply integrated into WCF.
The most important structural classes from the System.Identity­Model namespace that you need to understand are called Claim, ClaimSet, AuthorizationContext, and AuthorizationPolicy. We will now have a closer look at each of them and explore how they are integrated into the WCF security system.

A claim is a piece of information that can be associated with an entity in your system. This is most commonly a user but could also be a service or some resource. A claim consists of three pieces of information: a claim type, the claim content, and whether the claim describes the identity of the subject or a capability of the subject. This data structure is represented by a class known as System.IdentityModel.Claims.Claim. Furthermore, Claim is a DataContract, which makes it serialization-friendly (important when you plan to transmit claims over service boundaries):
[DataContract(Namespace = 'http://schemas.xmlsoap.org/ws/2005/05/identity')] public class Claim { [DataMember(Name = 'ClaimType')] public string ClaimType; [DataMember(Name = 'Resource')] public object Resource; [DataMember(Name = 'Right')] public string Right; }
ClaimType is a URI that identifies the claim type. While you can come up with your own type URI, several standard claim types are available from the ClaimTypes class. A claim representing a name could use the URI value held by ClaimTypes.Name:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
The Resource property contains the actual claim value. Note that the Resource is of type object—this means that you could associate arbitrarily complex information with that claim (from a simple string to a complete graph). Just keep in mind that this may become a problem when it comes to serialization, and if that is a concern, you should probably stick to primitive types. The purpose of the Right property will become clearer once we talk about claim sets.
You can create a new claim by either using the Claim constructor or taking advantage of one of the static methods on the Claim class (for standard claim types):
Claim purchaseLimitClaim = new Claim( 'http://www.leastprivilege.com/claims/purchaselimit', 5000, Rights.PossessProperty); Claim nameClaim = Claim.CreateNameClaim('Alice');

A claim usually doesn't arrive by itself. Claims are typically grouped in claim sets. The class ClaimSet holds a list of claims as well as a reference to the issuer of those claims:
[DataContract(Namespace='http://schemas.xmlsoap.org/ws/2005/05/identity')] public abstract class ClaimSet : IEnumerable<Claim>, IEnumerable { public abstract ClaimSet Issuer { get; } public abstract Claim this[int index] { get; } public static ClaimSet System { get; } public static ClaimSet Windows { get; } }
The issuer is an important concept once your distributed system gets more complex. Claims could come from various sources such as the current service, the calling service, or a security token service. Having an issuer associated with the set allows the service to distinguish between claim sources (which may also influence trust decisions).
An issuer is also described as a claim set, and System.IdentityModel ships with two predefined issuer claim sets called System (for claims coming from the system) and Windows (for claims coming from the Windows security subsystem). Both are available as static properties on the ClaimSet class.
Another important concept is the claim set's identity. A claim set typically needs a single claim that uniquely identifies the subject it describes. This is where the Right property on the Claim class comes into play. A claim set should have a single claim that has a Right value of Identity (this is the unique identifier) and a number of claims with a Right value of PossessProperty (additional claims describing the subject).
You can create your own claim sets by creating a DefaultClaimSet instance or, when you need more control, by deriving from the abstract class ClaimSet:
DefaultClaimSet myClaimSet = new DefaultClaimSet(ClaimSet.System, new List<Claim> { new Claim(ClaimTypes.Name, 'Alice', Rights.Identity), new Claim(purchaseLimitClaimType, 5000, Rights.PossessProperty), Claim.CreateMailAddressClaim(new MailAddress('alice@leastprivilege.com')) });
System.IdentityModel ships with two claim sets for converting Windows tokens and X.509 certificates to claims—these are WindowsClaimSet and X509CertificateClaimSet, respectively. These two claim sets are used by WCF for the Windows and Certificate client credential types.
ClaimSet provides two processing primitives for querying the claims: FindClaims and ContainsClaim. FindClaims returns a collection of claims for the specified claim type, whereas ContainsClaim gives you information about the existence of a specific claim.
Due to the general-purpose nature of claim sets, you will typically end up writing your own domain-specific extensions that work against the claim set data structure. Extension methods in C# 3.0 are a convenient way to extend these types with custom functionality. (I have written a library of extension methods for Claim, ClaimSet, and related types that you can download from leastprivilege.com/IdentityModel.)

AuthorizationContext
The last missing piece in the IdentityModel puzzle that you need to know before doing some real work with claims is the authorization context, which acts as a container for claim sets as well as transformation policies (more on this later). WCF makes the authorization context available via the thread-static ServiceSecurityContext. You can use the code snippet shown in Figure 5 to dump the claim sets and claims that are associated with the current service operation request.
public void ShowAuthorizationContext() { AuthorizationContext context = ServiceSecurityContext.Current.AuthorizationContext; foreach (ClaimSet set in context.ClaimSets) { Console.WriteLine('\nIssuer:\n'); Console.WriteLine(set.Issuer.GetType().Name); foreach (Claim claim in set.Issuer) { ShowClaim(claim); } Console.WriteLine('\nIssued:\n'); Console.WriteLine(set.GetType().Name); foreach (Claim claim in set) { ShowClaim(claim); } } } private void ShowClaim(Claim claim) { Console.WriteLine('{0}\n{1}\n{2}\n', claim.ClaimType, claim.Resource, claim.Right); }
When you place this code into a WCF service, you will see different output depending on the configured client credential type. If Windows authentication is enabled, the WCF-generated claim set will contain the user's SID (identity claim), the group's SIDs, and the user name. For a request that is authenticated using a client certificate, the claim set will contain claims that describe the subject name, public key, thumbprint (identity claim), expiration dates, and so on. For users that authenticate with a simple user name/password pair, there will be only a single user name identity claim.
So you can see that the WCF integrated claims layer converts technology-specific identity information, such as a Windows token or certificate, to a general-purpose data structure that can be queried using standard APIs. This makes writing services that have to support multiple credential types much easier—you are not hardwired to any technology-specific APIs anymore. If new credential types are added to WCF, the corresponding plumbing will take care of converting that proprietary format to claims as well.

Claims Transformation
Service operations typically don't care about the user's SID or certificate thumbprint, but they do care about domain-specific identity information such as a user identifier, e-mail address, or purchase limit. Claims transformation is the process of transforming the technology-specific identity details into application-specific ones.
Now that you have all identity information in a common format, it is easy to parse and analyze the claims information to create new claims that make more sense in the application context. Based on the identity claim of the WCF-generated claim set, you can map the request to an application user ID and add the relevant identity and authorization information to a new claim set. The service operation would then simply reach into the WCF authorization context to retrieve the information in which it is interested, as illustrated in Figure 6.

Figure 6 Claims Transformation (Click the image for a larger view)
Claims transformation is accomplished in an authorization policy. We have already used an authorization policy to create a custom principal, but this time it has a different purpose. Author­ization policies can take part in the claims-generation process and run after the WCF internal claims generation is completed. That means the claims associated with the caller's credentials are already accessible to you.
You can query the existing claims for identity information and, based on that, create a new claim set that models your domain-specific claims. Then you can add it to the list of claim sets. This list will be used to create the authorization context before the request reaches the service operation.
There are three members on the IAuthorizationPolicy interface that you have to implement. Id returns a unique identifier for the policy (usually a GUID), and Issuer returns a claim set describing the issuer of the claims that this policy creates. The most important method, however, is Evaluate. This method receives an evaluation context, which basically represents the authorization context while it is still in the process of being built.
You get access to all currently generated claims via EvaluationContext.ClaimSets. Don't try to touch the ServiceSecurityContext from within the Evaluate method, as this will trigger the authorization policies again and you'll end up in an infinite loop. You can add a new claim set to the evaluation context by calling EvaluationContext.AddClaimSet—this claim set will become part of the authorization context later on.
Figure 7 shows a sample authorization policy that implements a common pattern. It first retrieves the identity claim of the first claim set. This claim is sent to a mapping component, which inspects the claim and returns an application user ID. After that the policy hits a data store using the ID to retrieve the information that should become part of the claim set. This information is then packaged as a new claim set and added to the evaluation context.
class CustomerAuthorizationPolicy : IAuthorizationPolicy { Guid _id = Guid.NewGuid(); // custom issuer claim set ApplicationIssuerClaimSet _issuer = new ApplicationIssuerClaimSet(); public bool Evaluate(EvaluationContext evaluationContext, ref object state) { Claim id = evaluationContext.ClaimSets.FindIdentityClaim(); string userId = Map(id); evaluationContext.AddClaimSet(this, new CustomerClaimSet(userId)); return true; } public ClaimSet Issuer { get { return _issuer; } } public string Id { get { return 'CustomerAuthorizationPolicy: ' + _id.ToString(); } } }
The final step is to add the authorization policy to the serviceAuthorization behavior configuration. You can add multiple policies, and they are invoked in the order you add them. This means you can write multi-step authorization policies where one policy relies on values added by a previous one. This is pretty powerful for more complex scenarios:
<serviceAuthorization> <authorizationPolicies> <add policyType='LeastPrivilege.CustomerAuthorizationPolicy, Service' /> <add policyType='some_other_policy' /> </authorizationPolicies> </serviceAuthorization>
If you ran the previous code again to inspect the authorization context, you will see the new claim set and claims. The service operation would use similar code to check the claims for authorization (see Figure 8).
public void PlaceOrder(Order order) { int purchaseLimit = GetPurchaseLimit(); if (Order.Total > purchaseLimit) { // do appropriate action } } private int GetPurchaseLimit() { AuthorizationContext context = ServiceSecurityContext.Current.AuthorizationContext; foreach (ClaimSet set in context.ClaimSets) { foreach (Claim claim in set.FindClaims( Constants.PurchaseLimitClaimType, Rights.PossessProperty)) { return int.Parse(claim.Resource.ToString()); } } throw new Exception('Claim not found'); }
The service authorization manager also works with claims-based authorization. WCF passes the operation context into the CheckAccessCore method. From there you can reach into the service security context that will give you access to the authorization context. This allows you to centralize certain authorization decisions in a single place.

Security Token Services
A security token service (STS) is a tool that allows further consolidation of security logic. The typical task of an STS is to authenticate users and create a security token that, in turn, can contain claims. Clients must first authenticate with the STS and then forward the returned token to the service with which the client wants to communicate.
Since the STS knows about that service (this information is part of the token request), it can do central authorization as well as pre-generate the claims on which the service relies. This way the claims transformation does not need to happen on the service endpoint at all but can be done centrally by the STS. This can dramatically streamline your security infrastructure when your system reaches a certain level of complexity.
A security token service is also an important infrastructure component when it comes to federating multiple trust domains. By establishing trust between several token services, you can exchange security tokens over the trust boundary that can be used by services.
WCF has automatic client/service-side support for the previous scenario as well as all the base classes needed to write an STS. But correctly implementing all the related WS-* specs is a complicated task. Instead, you should either buy a commercial STS or use a higher-level toolkit, such as Zermatt, to write a custom one. The upcoming version of Microsoft Active Directory Federation Services is designed to be a full-featured STS for WCF.