3. 媒体服务认证 API
Microsoft® Windows Media™ Services 认证 API 设计用来提供创建定制的称之为认证者认证插件组件的基础.
1) 简介
认证进行在信息交互之前的用户校验. 当一个客户端初始化一个请求到认证使能的服务器, 服务器提示用户认证身分. 通常要求提供用户名和密码. 因此服务器和客户端必须都遵守一个约定协议.
服务器使用内置认证组件验证用户身分. Windows Media Services 绑定了几个相关插入组件. Windows Media Services 认证是基于COM的对象. 使用 Windows Media Services Authentication API 可以容易地创建一个新的验证者. 你也可以将其同 Windows Media Services 服务器进行无缝集成结合验证数据库用以验证客户端身分, 并且提示服务器输出.
每一个验证者设计用以实现一个类型的验证动作. 虽然可以有一种以上的验证方式注册在系统里面, 一次只可以使用一个方法.
Windows Media Services 需要一个支持 free-threading(COINIT_MULTITHREADED) 的COM组件. 这样, 当创建一个认证组件的时候, 你必须避免使用 apartment-threading (COINIT_APARTMENTHREADED) 模式的认证组件. 为了提供更好的性能和更好的扩展性, free-threading 并行模式缺乏线程安全特性. 因此, 作为COM组件的创建者, 你必须负责维护对象方法的串行化调用.
2) 验证类型
验证类型描述了用来交互认证信息的安全协议. 类型针对客户端而言, 提供了客户端需要的信息进行将需要同服务端交互的数据进行解释和组包. 不同的验证者可以术语同一个类型, 但是验证不同用户使用不同的验证数据库. 这样, 类型仅仅描述如何同其他信息交互而不是信息是如何进行验证的. 例如, 几个验证者可以使用 HTTP-BASIC 类型, 但是使用不同的用户数据库.
运行 Windows Media Services 和 Microsoft® Windows Media™ Player 的服务器支持两个内置的认证协议类型:
-- HTTP-BASIC 和 NTLM.
NTLM协议一个内置于NTLM数据库的基于请求/响应的方案. HTTP-BASIC 是一个基于文本的协议, 它通过 TCP/IP 传输 UUE 编码的用户名/密码字符. NTLM因此更加安全, 但是HTTP-BASIC更适合互联网上面的分布式系统. 而且NTLM只适用于NTLM数据库. 不同的认证者可以使用HTTP-BASIC则可以使用任意的数据库.
【HTTP-BASIC】
HTTP-BASIC 基于文本格式, 由用户名/密码组成. 在该协议下, 客户端在尝试打开一个标题的时候接收一个认证错误信息. Windows Media Player 通过显示一个对话框允许用户输入用户名/密码. 服务器接收用户名/密码将它们传递给验证者(使用BASE64编码的字符串). 验证者经由用户数据库检查用户身分, 并且提示服务器验证结果. 如果验证的用户在不同于服务器所在的域, 用必须依照"域名\用户名"的格式提供.
HTTP-BASIC 协议适用于互联网应用程序. 它可以可以容易适用于定制的或者现有的用户数据库. 验证者可以被设计接收客户端身分信息并且结合任意名域进行比配.
【NTLM】
当一个用户试图打开一个标题的时候, NTLM 认证被使能, 服务器使用一个加密的请求/响应方案用以验证当前会话的用户身分. 因为NTLM使用用户登陆建立连接的认证信息, 它需要客户端和服务器在同一个域或者相互信任的域之间. NTLM 无需传输用户的身分信息就可以完成验证, 即服务器无需访问用户名/密码. NTLM 更适合Intranet应用程序.
请求/响应方案包括如下组成:
- 客户端首先打开一个服务器上的标题, 并且接收一个认证错误信息.
- 客户端收到认证错误信息以后, 发送其域名和计算机名到服务器. 服务器将数据传递给认证者
- 认证者回传 NTLM 请求, 而服务器将数据返回客户端.
- 客户端通过发送 NTLM challenge/response 到服务器进行响应. 服务器将数据传递给认证者检查
- 认证者检查NTLM用户账号数据库的身分入口, 提示服务器结果. 服务器根据结果授予/拒绝访问.
3) 认证接口
Windows Media Services Authentication API 由三个COM兼容的接口组成. 这些接口定义服务器和验证者如何配合工作. 验证者必须实现针对服务器实现其中的两个接口来调用他们的方法. 服务器实现其余的接口—一个回调接口—经由验证者调用. 运行 Windows Media Services 的服务器也调用几个上下文对象来实现 IPropertyMap -- 一个预组包通用接口来维护命名参数.
- INSSAuthenticator
用以实现验证者的初始化, 创建一个用户验证对象, 然后指定的验证类型. 验证者实现该接口, 而服务器调用这些方法
- INSSUserAuthentication
用以检查传自客户端到服务器的认证数据, 该接口也提供必要的方法给服务器来模拟客户端访问控制检查. 认证者实现该接口, 而服务器调用其方法.
- INSSAuthenticationCallback
用以告知服务器验证结果. 服务器实现该接口, 而验证者调用方法.
4) 如何使用认证API
【过程】
- 初始化
服务器启动的时候查询注册验证组件. 当启动成功, 服务器取得CLSID创建实例. 然后服务器调用Initialize方法初始化实例对象, 将一个指针传递给服务器上下文. 这个上下文包含了描述服务器特性的属性. 这些熟悉至少包含:
1. 服务器名和别名
2. 版本号
Initialize 方法提供了验证者机会来执行任意预备验证工作, 诸如建立一个到用户账号数据库的连接, 并且分配验证者需要的系统资源.
初始化期间, 验证者也告知服务器是否客户端的交互数据是基于文本的, HTTP-BASIC 基于文本, 而 NTLM 是二进制.
注意: 在服务器启动的时候, Initialize() 方法总是在所有的验证者组件上被调用. 该方法即使在组件被禁止的时候也调用. 作为一个结果, 如果任意禁止组件返回一个失败代码, 服务器依旧启动, 但是没有足够的信息提供给认证任务进行活动.
- 获得认证类型
初始化以后, 服务器调用 GetAuthenticationType 方法获得验证者使用的认证类型. 该类型必须可以为 Windows Media Player 所识别. 目前 Windows Media Player 简介支持 HTTP-BASIC 和 NTLM
- 使用认证对象
由一个验证者管理的用户验证对象实现 INSSAuthenticator 接口, 在每次用户连接的时候检查和验证用户信息. 每一个连接到服务器的用户创建不同的验证对象. 服务器调用验证者的 CreateUserAuthentication 方法创建一个用户验证对象. 用户连接实例的验证通过用户认证对象实现.
- 认证如何工作
每次一个用户端建立一个打开标题请求, 服务器提示 Windows Media Player 用户需要验证. 不管使用何种验证信息, 验证总是包含和客户端, 服务器和验证者之间的数据交互. 服务器从客户端获得数据, 诸如用户名/密码, 传递数据给验证者进行检查. 验证者使用这些数据请求服务器传递给用户账号数据库, 并且通过 callback 方法提示服务器验证结果.
数据交互不断持续知道要么验证者通过 callback 方法提示服务器验证接收, 要么出现错误. 理论上, 数据交互可以永久程序, 但是大多数验证方案仅仅重复一到三次.
Windows Media Player 提示用户输入用户名/密码, 将数据发布到服务器, 服务器然后传递给验证者进行检查, 沿着这使用其自己的私有用户数据库验证数据, 并且提示服务器结果. 服务器然后根据结果授予或者剥夺客户端访问数据的权力.
- 认证后
认证以后, 组件提示服务器结果, 附带传递给用户认证上下文一个指针. 用户表示被验证, 服务器复制该指针进入用户上下文的 NSS_USER_AUTHENTICATION 属性. 认证结果和用户名通过 INSSUserAuthentication 接口取得.
当服务器成功进行认证, 它可以在任何需要的时候模拟客户端用户.
【注册验证者】
通过安装 Windows Media Services 组件, 下列键被键入注册表:
[HKEY_LOCAL_MACHINE\Software\Microsoft\NetShow\Servers\\Default\Authentication]
启动的时候, 服务器检测注册表和实例化键下的使能认证者列表.
下列代码衍射了一个需要键入认证键的数据:
[HKEY_LOCAL_MACHINE\Software\Microsoft\NetShow\Servers\\Default\Authentication\Sample Authentication Module]
"CLSID"="{16DA4310-2955-11D1-9E98-006097D2D7CF}"
"Description"="Sample Authentication module"
"Author"="Developer Name"
"Copyright"="(c) Developer 1998"
"Enabled"=dword:00000001
CLSID 和 Enabled 键值是必须的. 其余的值是推荐的.
服务器检逐个查注册表中的验证者清单的每一个验证者, 一旦遇到一个使能验证者, 服务器调用并且使用到停止和重启的时候为止.
4. 媒体服务事件提示和认证 API
Microsoft® Windows Media™ Services 提供一个 API 用以开发时间提示和认证组件. 这些组件通过提供工具来认证正在播出的内容, 监视服务器状态, 审核任务扩展了服务器功能.
1) 简介
作者行为指的是为创建使用的一种安全机制, 用来授权或者剥夺对于受保护的资源的访问权限. 对于 Windows Media Services 类似的例子有 Pay-per-View (PPV), Pay-per-Minute (PPM) 等, 和免费但是敏感的内容. 作者行为偕同认证行为一起工作. 通常一个用户如果认证失败就不具备访问请求资源的权力. 一个内容提供商可以选择是否授权一个已认证用户有限/无限的访问请求的标题.
通告行为, 从另一个角度指的是为服务器所使用的用来停止创建任意需要记录的时间, 或者其他类型的需要报告的信息.
服务器通过使用插件执行认证和通告任务. 根据不同商业要求插件提供不同的认证方案. 运行 Windows Media Services 的服务器支持同时运行任意数量的创建. 每一个创建可以指定一个特定的认证/通告事件集合.
Windows Media Services 事件通告和认证API使你能通过提供一个插件协议来创建适合你的商业要求的解决方案. 这些插件在特定事件触发认证行为. API 让你可以协调已经建立的应用程序的结构.
针对 Windows Media Services 的 COM 组件必须支持 free-threading (COINIT_MULTITHREADED) 模式. 这样, 当创建一个认证组件的时候不要使用 apartment-threading (COINIT_APARTMENTHREADED). 为了提供更好的性能和扩展性, free-threading 同步模式是缺乏线程安全特性的. 这样作为组件的创建者, 必须负责对于对象方法的串行化调用.
作为 COM 对象, 这些创建必须在实例化之前正确注册. 启动的时候服务器检测组件决定何种类型的事件需要认证和通告. 当一个客户端提出请求, 服务器视图触发一个特定的事件, 并且请求相关组件执行响应. 在执行授权/撤销之后, 服务器提示组件事件的输出.
例如, 组件可以指定 Play 事件需要认证和通告. 当一个客户端请求服务器 Play 一个标题, 服务器从组件查询许可, 然后尝试在授权之前进行一个安全的偿付计划. 如果认证成功, 服务器开始播发标题, 通知组件该 Play 事件触发. 组件审核播发事件进行计费.
2) 事件通告和认证接口
Windows Media Services Event Notification and Authorization API 由三个接口组成: 认证组件实现 INSSEventNotification , INSSEventAuthorization. 服务器实现 INSSEventAuthorizationCallback, 并且它的方法为组件调用. 还要实现基本的 IUnknown 接口的 AddRef, Release, QueryInterface.
运行 Windows Media Services 的服务器也包含几个上下文对象, 它们实现 IPropertyMap -- 一个通用的预组包的接口, 用来维护命名参数.
接口简介:
- INSSEventNotification
用于初始化整个认证组件, 指定来自服务器调用的事件, 并且处理通告事件. 组件实现该接口, 服务器调用.
- INSSEventAuthorization
用于指定那个事件必须在执行之前得到验证, 处理认证事件. 组件实现, 服务器调用
- INSSEventAuthorizationCallback
通知服务器认证处理结果. 服务器实现, 组件调用.
认证组件必须能够处理和认证一样处理事件. 这样每一个组件必须实现 INSSEventNotification. 每一个组件可以选择性地响应服务器触发地事件. 你实现 INNSEventNotification::GetHandledEvents 方法指定需要发送的通告的事件类型. 除了处理事件, 事件通告接口还在服务器启动的时候初始化组件, 监视服务器的执行状态和在服务器离线的时候终止自身.
INSSEventAuthorization 接口仅仅处理认证事件. 仅仅在需要认证的时候实现该接口的组件. 由两个方法:
- INSSEventAuthorization::GetAuthorizedEvents
指定请求认证的事件类型
- INSSEventAuthorization::AuthorizeEvent
执行认证. 一个事件可以请求认证, 但是不能通知; 反过来一样.
对于认证事件可以注册任意数量的组件. 此时服务器依次调用组件的认证接口方法. 服务器值得得到所有组件的许可才进行授权; 否则解决授权, 并且通知所有组件.这样, 组件必须给予所有职权范围之外的认证请求以授权.
从性能角度考虑, 单一组件处理不同认证方案的能力优于多重组件处理一个单一认证方案. 单一组件实现有助于降低不同插件和服务器之间的接口数量.
工作流程:
- 初始化
启动的时候服务器检索系统注册表获得所有安装的事件通告和认证创建列表, 启动成功以后, 服务器利用CLSID创建实例. 然后调用各个组件的 INSSEventNotification::Initialize 方法初始化实例对象, 传递一个指针给服务器上下文. 该上下文对象包含描述特定服务器特性的属性:
服务器名称, 服务器虚拟名称, 服务器版本号
服务器上下文对象在服务器运行期间有效. 然后服务器可以传递福建上下文到组件, 诸如一个用户上下文对象或者一个表达式上下文对象.
注意: 在服务器启动期间, Initialize() 方法总是在所有服务器配置的组件上面调用, 即使被禁止. 结果, 如果任意禁止创建返回失败, 服务器依旧启动, 但是因为没有进行认证工作的足够信息无法实现流.
- 设置一个心跳
心跳为一个插件用来定时其他事件以监视服务器执行状态. 你可以让服务器通过指定一个dwMsHearbeatPeriod参数正值并且在INSSEventNotification::Initialize方法中回传服务器达到使能心跳的目的. 如果心跳使能, 服务器在心跳周期之间调用 INSSEventNotification::OnHeartBeat 方法. 设置 dwMsHeartbeatPeriod 参数为0禁止心跳.
- 指定通告事件
初始化以后, 服务器调用每一个组件的 INSSEventNotification::GetHandledEvents 方法. 该方法用来指定那些事件经由服务器触发调用: 客户端连接/断开服务器, 打开/关闭标题, 启动停止标题, 跳过或者使能客户端认证
- 测试认证支持
在设置认证事件以后, 服务器调用 INSSEventAuthorization::QueryInterface 方法绝对是否认证接口被支持. 所有组件必须实现 INSSEventNotification. 然而, 实现 INSSEventAuthorization 是可选的. 当认证被支持, 服务器调用 INSSEventAuthorization::GetAuthorizedEvents 方法获得认证事件数组, 然后决定哪个事件需要认证.
- 指定认证事件
组件指定那些事件必须被认证. 使用 INSSEventAuthorization::GetAuthorizedEvents 方法实现认证方案. 该方法和指定通告事件类似. 但是针对认证的事件更少而已. 比如, 在客户端断开之前请求认证就不现实, 因为服务器无法组织客户端断开.
你可以指定下列事件需要认证: 客户端连接到服务器, 打开一个标题, 播发一个标题, 跳过客户端认证
- 认证
运行 Windows Media Services 的服务器调用 INSSEventAuthorization::AuthorizeEvent 方法来决定是否执行和任务相关联的事件请求认证. 当调用该方法, 服务器使用事件, 客户端和需要认证的内容的相关信息被提供给组件.
如果认证复杂且冗长, 异步实现 AuthorizeEvent 方法, 启用另一个线程决定是否请求必须核准. 异步实现导致一个即使调用返回, 而且使得服务器可以在认证期间自由处理其他任务. 而如果认证简单, 该方法就必须是同步的.
在认证的最后, 认证组件调用服务器的 INSSEventAuthorizationCallback::OnEventAuthorized 方法. 服务器回传一个指向 INSSEventAuthorizationCallback 的指针. 认证组件不管 AuthorizeEvent 方法的同步/异步返回都必须调用该方法. 如果 AuthorizeEvent 方法失败, 不会有回调发生.
要唯一性表示请求认证事件, 服务器和认证组件都互相传递 dwRequestId 参数. 服务器通过 INSSEventAuthorization::AuthorizeEvent 方法传递. 认证组件必须通过 INSSEventAuthorizationCallback::OnEventAuthorized 回传同样参数给服务器.
- 传递动态数据给认证者
也可以使用运行时动态产生的数据执行认证. 客户端可以通过流的 URL 传递额外的信息. 服务器在解析 URL 和决定那个文件流向客户端的时候忽略(?)后面的所有字符. 无论如何, 字符串并存在 Presentation Context 的 NSS_PRESENT_PHYSICAL_NAME 属性中. 认证组件负责解析字符串.
例如, 用户需要查看标题为 TrainingABC.asf 的本地服务器上的文件. 用户提供如下:
mms://localhost/TrainingABC.asf
从另一个角度, 认证者在运行时可以选择不使用数据库, 但是基于用户的私人信息, 诸如用户名称和雇佣信息. 用户可以这样达到目的:
mms://localhost/TrainingABC.asf?USER=Joe;ID=2316
如果标题几节 A, B, C—可以书写一个核准让用户选择那个节:
mms://locahost/TrainingABC.asf?LESSON=B
- 事件提示
服务器也可以使用 INSSEventNotification::GetHandledEvents 提示组件任意注册事件. 通告指定了了事件请求类型和认证结果.
你可以选择 INSSEventNotification::OnEvent 进行不同响应.
假设一个用户选择播发一个标题, 并且该是被一个组件注册为通告和认证的. 服务器请求该组件核查用户. 用户在被认证播发标题以后, 服务器就为用户打开标题, 否则就不打开. 如果不需要认证, 服务器在为用户打开标题以后也通知组件该标题正在被播发.
对于多个注册的使能组件, 服务器逐个查询认证. 只有所有组件提供授权时, 事件才允许发生, 然后提示每一个组件.
如果有任意组件拒绝请求, 服务器停止查询进程于第一个拒绝对象. 认证失败, 服务器于是不使能事件. 服务器提示所有协商组件该事件未发生.
注意: 如果你允许基于 HTTP 的流访问 -- 单播, 可能导致在针对 -- 连接, 打开和播放的多重认证和通. 这是因为, 在 HTTP 使用的时候, 客户端使用分散的 HTTP 请求获得 ASF的头部和身体. 对于服务器, 这些是多重请求. 你的事件通告和认证组件必须提供这种情况的正确处理. 当 HTTP 替代 MMS, 该行为是的它变得困难, 虽然是可行的.
3) 注册事件通告和认证组件
相对路径
[HKEY_LOCAL_MACHINE\Software\Microsoft\NetShow\Servers\Default\Event Notification]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Media\Servers\Default\Event Notification\Sample Billing Module]
"CLSID"="{16DA4310-2955-11D1-9E98-006097D2D7CF}"
"Description"="Sample billing module"
"Author"="Developer Name"
"Copyright"="(c) Developer 1997"
"Enabled"=dword:00000001
注意: 每一个插件都支持事件通告, 而认证是可选的. 服务器调用 QueryInterface 判断组件师父支持认证. 不能添加无用信息, 否则服务器在检测注册表失败的时候会停止允许建立新的连接.
4) 上下文对象
上下文对象是一个实现 IPropertyMap 接口的对象, 维护一组数据. 当封装的数据定义服务器, 用户或者其他内容, 就是 server context, user context, presentation context, 或者 command context.
关键词:Windows Media server SDK (2)