Token导航 LogoToken导航TokenDH.com
MCP Abap Adt Auth Providers logo
安全风控未说明官方级别未说明来源级核验

MCP Abap Adt Auth Providers

MCP Server

为MCP ABAP ADT auth-broker提供OAuth2和SAML2令牌获取与验证功能的Node.js模块。

工具数

0

提示词数

0

GitHub Stars

0

资源数

0
TypeScriptCline安全Cline

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

作者 / 组织

fr0ster

提供方

fr0ster

最后核验

2026/5/17 20:20

快速接入

先看主来源和安装命令,再打开仓库或文档;下面只保留这个条目的关键接入事实。

详细介绍

@mcp-abap-adt/auth提供者

![Stand With Ukraine](https://stand-with-ukraine.pp.ua)

MCP ABAP ADT身份验证代理的令牌提供者。

此包为提供令牌提供者实现 @mcp-abap-adt/auth-broker 包裹。

安装

npm install @mcp-abap-adt/auth-providers

概述

此包实现了 ITokenProvider 接口来自 @mcp-abap-adt/interfaces:

  • 授权码提供者 -使用基于浏览器的OAuth2授权代码流(用户令牌)
  • 客户端认证提供者 -用途 client_credentials 授权类型(无需浏览器)

提供者是通过构造函数配置的; getTokens() 不接受任何参数,并在内部处理刷新/登录。

责任和设计原则

核心开发原则

仅接口通信该方案遵循一个基本的发展原则: 所有与外部依赖关系的交互都只能通过接口进行代码知道 没有超出接口中定义的内容.

这意味着:

  • 不知道其他包中的具体实现类
  • 不了解接口中未定义的内部数据结构或方法
  • 不假设接口契约之外的实现行为
  • 不访问接口中未明确定义的属性或方法

这一原则确保:

  • 松散结合:提供者与其他包中的具体实现解耦
  • 灵活性:可以添加新的实现,而无需修改提供程序
  • 可测试性:易于模拟测试依赖关系
  • 可维护性:对实现的更改不会影响提供者

包装责任

该包负责:

  1. 实现令牌提供者接口:提供以下内容的具体实施 ITokenProvider 接口定义于 @mcp-abap-adt/interfaces
  2. 代币获取:处理OAuth2流(基于浏览器、刷新令牌、客户端凭据)以获取JWT令牌
  3. 令牌验证:通过检查exp声明(无HTTP请求)在本地验证JWT
  4. OAuth2流:管理基于浏览器的OAuth2授权代码流和刷新令牌流

这个包有什么作用

  • 实现ITokenProvider:提供具体实施(AuthorizationCodeProvider, ClientCredentialsProvider)
  • 处理OAuth2流:基于浏览器的OAuth2、刷新令牌和客户端凭据授予类型
  • 获得代币:向UAA端点发出HTTP请求以获取JWT令牌
  • 验证令牌:通过检查exp声明(无HTTP请求)在本地验证JWT
  • 返回令牌:退货 ITokenResult 随着 authorizationToken 可选 refreshToken

此软件包不做什么

  • 不存储令牌:令牌存储由以下人员处理 @mcp-abap-adt/auth-stores
  • 不编排身份验证:令牌生命周期管理由以下人员处理 @mcp-abap-adt/auth-broker
  • 不知道维修钥匙:服务密钥加载由商店处理
  • 不管理会话:会话管理由商店处理
  • 不返回 serviceUrl 如果未知:供应商可能不会返回 serviceUrl 因为它们只处理令牌获取,不处理连接配置

外部依赖

此包与外部包交互 仅通过接口:

  • @mcp-abap-adt/auth-broker:使用接口(ITokenProvider, IAuthorizationConfig)-不知道 AuthBroker 实施
  • @mcp-abap-adt/logger:用途 Logger 日志记录接口-不了解具体的日志记录器实现
  • @mcp-abap-adt/connection:使用连接实用程序进行令牌验证-通过定义良好的函数进行交互
  • 不直接依赖商店:与商店的所有交互都是通过消费者传递的接口进行的

用法

基本用法

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { AuthorizationCodeProvider, ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';

// User token via authorization_code (browser flow)
const authCodeBroker = new AuthBroker({
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
  }),
});

// Service token via client_credentials (no browser)
const clientCredsBroker = new AuthBroker({
  tokenProvider: new ClientCredentialsProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
  }),
}, 'none');

SSO提供者

该软件包还包括用于OIDC和SAML2的SSO提供程序,以及一个用于DI友好创建的小型工厂。

可用提供商:

  • OidcBrowserProvider (授权码+PKCE)
  • OidcDeviceFlowProvider
  • OidcPasswordProvider
  • OidcTokenExchangeProvider
  • Saml2BearerProvider (SAML断言交换)
  • Saml2PureProvider (返回SAMLResponse作为令牌)

工厂示例:

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { SsoProviderFactory } from '@mcp-abap-adt/auth-providers';

const tokenProvider = SsoProviderFactory.create({
  protocol: 'oidc',
  flow: 'browser',
  config: {
    issuerUrl: 'https://example-idp/.well-known/openid-configuration',
    clientId: '...',
    clientSecret: '...',
    scopes: ['openid', 'profile', 'email'],
    browser: 'system',
  },
});

const broker = new AuthBroker({ tokenProvider }, 'none');

OIDC浏览器示例(手动代码+显式端点):

import { OidcBrowserProvider } from '@mcp-abap-adt/auth-providers';

const provider = new OidcBrowserProvider({
  clientId: '...',
  tokenEndpoint: 'https://issuer/oauth/token',
  authorizationEndpoint: 'https://issuer/oauth/authorize',
  authorizationCode: '
',
  redirectUri: 'urn:ietf:wg:oauth:2.0:oob',
});

SAML承载示例(手动流程):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2BearerProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2BearerProvider({
  assertionFlow: 'manual',
  idpSsoUrl: 'https://idp.example.com/sso',
  spEntityId: 'my-sp-entity',
  uaaUrl: 'https://uaa.example.com',
  clientId: '...',
  clientSecret: '...',
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

SAML承载示例(无头,断言提供者):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2BearerProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2BearerProvider({
  assertionFlow: 'assertion',
  assertionProvider: async () => {
    return getSamlResponseFromSsoProxy();
  },
  uaaUrl: 'https://uaa.example.com',
  clientId: '...',
  clientSecret: '...',
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

纯SAML示例(基于cookie):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2PureProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2PureProvider({
  assertionFlow: 'manual',
  idpSsoUrl: 'https://idp.example.com/sso',
  spEntityId: 'my-sp-entity',
  // Convert SAMLResponse to session cookies for SAP (implementation-specific)
  cookieProvider: async (samlResponse) => {
    return exchangeSamlForCookies(samlResponse);
  },
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

与商店

重要:BTP和ABAP是不同的实体:

  • 业务流程平台 (基础BTP)-用途 BtpServiceKeyStoreBtpSessionStore (无 sapUrl)
  • ABAP -用途 AbapServiceKeyStoreAbapSessionStore (与 sapUrl)
import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { AuthorizationCodeProvider, ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';
import { 
  XsuaaServiceKeyStore, 
  XsuaaSessionStore,
  BtpServiceKeyStore,
  BtpSessionStore,
  AbapServiceKeyStore,
  AbapSessionStore 
} from '@mcp-abap-adt/auth-stores';

// XSUAA provider with stores (client_credentials or auth code)
const xsuaaServiceKeyStore = new XsuaaServiceKeyStore('/path/to/service-keys');
const xsuaaSessionStore = new XsuaaSessionStore('/path/to/sessions');

const xsuaaBroker = new AuthBroker({
  serviceKeyStore: xsuaaServiceKeyStore,
  sessionStore: xsuaaSessionStore,
  tokenProvider: new ClientCredentialsProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
  }),
}, 'none');

// BTP provider with stores (base BTP, without sapUrl)
const btpServiceKeyStore = new BtpServiceKeyStore('/path/to/service-keys');
const btpSessionStore = new BtpSessionStore('/path/to/sessions');

const btpBroker = new AuthBroker({
  serviceKeyStore: btpServiceKeyStore,
  sessionStore: btpSessionStore,
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
  }),
});

// ABAP provider with stores (with sapUrl)
const abapServiceKeyStore = new AbapServiceKeyStore('/path/to/service-keys');
const abapSessionStore = new AbapSessionStore('/path/to/sessions');

// Use custom port if running alongside other services (e.g., proxy on port 3001)
const abapBroker = new AuthBroker({
  serviceKeyStore: abapServiceKeyStore,
  sessionStore: abapSessionStore,
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
    redirectPort: 4001,
  }), // Custom port to avoid conflicts
});

令牌提供商

授权码提供者

使用基于浏览器的OAuth2流或刷新令牌:

import { AuthorizationCodeProvider } from '@mcp-abap-adt/auth-providers';

const provider = new AuthorizationCodeProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
  browser: 'system',
});

// If refreshToken is provided here, uses refresh flow (no browser)
// Otherwise, opens browser for OAuth2 authorization
const result = await provider.getTokens();

// result.authorizationToken contains the JWT token
// result.refreshToken contains refresh token (if browser flow was used)

客户端认证提供者

用途 client_credentials 授权类型-无需浏览器交互:

import { ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';

const provider = new ClientCredentialsProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
});

const result = await provider.getTokens();

// result.authorizationToken contains the JWT token
// result.refreshToken is undefined (client_credentials doesn't provide refresh tokens)

备注:The browserAuthPort 参数(默认值:3001)配置OAuth回调服务器端口。如果请求的端口已在使用中,将抛出错误。在开始身份验证之前,您必须指定其他端口或释放该端口。服务器在身份验证完成后正确关闭所有连接并释放端口,确保没有持久的端口占用。

超时:浏览器身份验证有30秒的超时时间,以防止阻止消费者。如果身份验证未在30秒内完成,则操作将失败并出现超时错误。这可以防止在用户未完成身份验证时提供程序无限期挂起。

流程终止处理:OAuth回调服务器为以下对象注册清理处理程序 SIGTERM, SIGINT, SIGHUP,以及 exit 信号。这确保了即使MCP客户端(如Cline)在身份验证完成之前终止进程,端口也能正确释放。这对于stdio服务器尤其重要,因为客户端可能随时终止进程。在Windows上 SIGBREAK 信号(Ctrl+Break)也被处理。

跨平台浏览器支持:浏览器身份验证适用于Linux、macOS和Windows:

  • Linux:自动设置 DISPLAY=:0 如果两者都没有 DISPLAY 也不 WAYLAND_DISPLAY 设置环境变量。支持多个浏览器可执行文件名(google-chrome, google-chrome-stable, chromium, chromium-browser Chrome; firefox, firefox-esr Firefox)。
  • 视窗:使用得当 cmd /c start "" 用于可靠打开浏览器的语法。
  • macOS:使用本地 open -a 命令。

无头模式(SSH/远程):对于没有显示器的环境(SSH会话、Docker、CI/CD),请使用 browser: 'headless':

const result = await provider.getTokens();

在无头模式下,记录身份验证URL,服务器等待用户手动完成身份验证。用户可以在任何机器上打开URL,服务器将收到回调。

浏览器选项:

  • 'system' (默认):打开系统默认浏览器
  • 'headless':记录URL,等待手动回调(SSH/remote)
  • 'none':记录URL,立即拒绝(自动测试)
  • 'chrome', 'edge', 'firefox':打开特定浏览器

令牌验证

供应商可以执行 本地JWT验证 通过检查 exp (到期)索赔:

const isValid = await provider.validateToken(token, serviceUrl);
  • 未向SAP服务器发出HTTP请求
  • 退货 true 如果令牌具有有效的JWT格式,并且 exp 未来(60秒缓冲)
  • 退货 false 如果令牌已过期、格式无效或将在60秒内过期
  • 网络问题(ECONNREFUSED、超时)不会触发令牌刷新
  • HTTP错误(401/403)由中的重试机制处理 makeAdtRequest 包装器
// Local validation (no HTTP)
const provider = new AuthorizationCodeProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
});
const isValid = await provider.validateToken(token);  // serviceUrl optional
// Checks JWT exp claim locally, no network request

在以下情况下,这种方法可以防止不必要的令牌刷新和浏览器身份验证:

  • 服务器无法访问(ECONNREFUSED,超时)
  • 网络速度慢或不稳定
  • 在离线/断开连接模式下运行

令牌刷新

提供者在内部自动处理刷新 getTokens()。不需要单独的刷新方法。

try {
  const result = await provider.getTokens();
  // Returns new access token and refresh token (if available)
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Missing fields:', error.missingFields);
  } else if (error instanceof RefreshError) {
    console.error('Browser auth failed:', error.cause);
  }
}

错误处理

该包提供了类型化的错误类,以更好地处理错误:

import {
  TokenProviderError,
  ValidationError,
  RefreshError,
  SessionDataError,
  ServiceKeyError,
  BrowserAuthError,
} from '@mcp-abap-adt/auth-providers';

try {
  const result = await provider.getTokens();
} catch (error) {
  if (error instanceof ValidationError) {
    // provider config validation failed
    console.error('Missing required fields:', error.missingFields);
    console.error('Error code:', error.code); // 'VALIDATION_ERROR'
  } else if (error instanceof RefreshError) {
    // Token refresh operation failed
    console.error('Refresh failed:', error.message);
    console.error('Original error:', error.cause);
    console.error('Error code:', error.code); // 'REFRESH_ERROR'
  } else if (error instanceof BrowserAuthError) {
    // Browser authentication failed
    console.error('Browser auth failed:', error.cause);
  }
}

错误类型:

  • TokenProviderError -基类与 code: string 财产
  • ValidationError -提供程序配置验证失败,包括 missingFields: string[]
  • RefreshError -令牌刷新失败,包括 cause?: Error
  • SessionDataError -会话数据无效,包括 missingFields: string[]
  • ServiceKeyError -服务密钥数据无效,包括 missingFields: string[]
  • BrowserAuthError -浏览器身份验证失败,包括 cause?: Error

所有错误代码均在中定义 @mcp-abap-adt/interfaces 包装为 TOKEN_PROVIDER_ERROR_CODES.

测试

该包包括单元测试(带模拟)和集成测试(带真实文件和服务)。

单元测试

npm test

集成测试

集成测试使用来自的真实文件 tests/test-config.yaml:

  1. 复制 tests/test-config.yaml.templatetests/test-config.yaml
  2. 填写真实目的地名称
  3. 运行测试-如果已配置,集成测试将使用真实服务
# Destination name (used for service key file: .json and session file: .env)
destination: "trial"  # Example: "trial" -> looks for trial.json and trial.env

# Optional: Destination directory (base directory for service keys and sessions)
# If not specified, uses default platform paths:
#   Unix: ~/.config/mcp-abap-adt
#   Windows: %USERPROFILE%\Documents\mcp-abap-adt
# Uncomment and set if you need a custom path:
# destination_dir: ~/.config/mcp-abap-adt

如果出现以下情况,集成测试将跳过 test-config.yaml 未配置或包含占位符值。

测试场景:

  • 场景1和2:令牌生命周期-通过浏览器登录并重用之前场景中的令牌
  • 情景3:会话过期+刷新令牌过期-提供者应通过浏览器重新进行身份验证
  • 令牌验证:在所有情况下明确验证令牌过期

备注:

  • 集成测试使用 AbapServiceKeyStoreAbapSessionStore 用于加载服务密钥和会话
  • 如果没有可用的刷新令牌,测试可能会打开浏览器进行身份验证。这是预期的行为。
  • 每个测试场景都使用一个唯一的端口(3101、3102、3103)来避免端口冲突
  • 测试使用 browser: 'system' 用于交互式身份验证(不是 'none')

调试日志记录

要在测试或运行时启用详细的日志记录,请设置环境变量:

# Enable logging for auth providers (short name)
DEBUG_PROVIDER=true npm test

# Or use long name (backward compatibility)
DEBUG_AUTH_PROVIDERS=true npm test

# Or enable via general DEBUG variable
DEBUG=true npm test

# Or include in DEBUG list
DEBUG=provider npm test
# Or
DEBUG=auth-providers npm test

# Set log level (debug, info, warn, error)
LOG_LEVEL=debug npm test

日志记录用途 @mcp-abap-adt/logger 带有结构化日志记录的软件包:

  • 代币交换阶段(我们发送什么,我们接收什么)
  • 令牌信息(长度、预览、过期)
  • 令牌验证检查(过期、有效性)
  • 详细信息错误

输出示例:

[INFO] ℹ️ [browserAuth] Exchanging code for token...
[INFO] ℹ️ Tokens received: accessToken(2263 chars), refreshToken(34 chars)
[DEBUG] 🐛 [BaseTokenProvider] Token validation check {"expiresAt":"2025-12-25 11:08:15 UTC","isValid":true}
[INFO] ℹ️ [browserAuth] Authorization URL: https://.../oauth/authorize?...
[INFO] ℹ️ [browserAuth] Browser: system

日志记录功能:

  • 令牌格式:为了安全起见,令牌以截断格式(开始…结束)记录
  • 日期格式:过期日期以可读格式(YYYY-MM-DD HH:MM:SS UTC)显示,而不是ISO格式
  • 浏览器信息:记录浏览器类型和授权URL以进行调试
  • 代币生命周期:令牌获取、验证和刷新操作的详细日志记录

依赖项

  • @mcp-abap-adt/interfaces (^0.2.2)-接口定义和错误代码常量
  • axios -HTTP客户端
  • express -OAuth2回调服务器
  • open -浏览器打开实用程序

许可证

麻省理工学院

目录标签

目录标签

TypeScriptCline安全OAuth2认证本地部署SAML2认证令牌管理ABAP开发安全模块

支持客户端

Cline

接入字段

传输方式(transport,传输协议)

未说明

鉴权方式(authType,认证方式)

oauth

工具数量(toolCount,工具数)

0

资源数量(resourceCount,资源数)

0

提示词数量(promptCount,提示词数)

0

权限和风险

未说明oauth部署方式未说明

接入前请确认传输方式、认证方式和部署位置,并根据实际工具能力限制访问范围。

安装前确认

不要直接授予不必要的文件、网络或账号权限;先核对安装命令和配置内容。

仍需确认:installCommand

来源信息

继续浏览同类 MCP