fa-mcp-sdk 0.2.121 → 0.2.125
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/fa-mcp.js +1 -0
- package/cli-template/config/_local.yaml +21 -1
- package/cli-template/config/custom-environment-variables.yaml +11 -1
- package/cli-template/config/default.yaml +11 -1
- package/cli-template/fa-mcp-sdk-spec.md +385 -2
- package/cli-template/package.json +72 -73
- package/cli-template/src/_examples/custom-basic-auth-example.ts +252 -0
- package/cli-template/src/_examples/multi-auth-examples.ts +333 -0
- package/cli-template/src/custom-resources.ts +1 -0
- package/cli-template/yarn.lock +6375 -0
- package/dist/core/_types_/TNtlm.d.ts +5 -0
- package/dist/core/_types_/TNtlm.d.ts.map +1 -0
- package/dist/core/_types_/TNtlm.js +2 -0
- package/dist/core/_types_/TNtlm.js.map +1 -0
- package/dist/core/_types_/config.d.ts +88 -0
- package/dist/core/_types_/config.d.ts.map +1 -0
- package/dist/core/_types_/config.js +2 -0
- package/dist/core/_types_/config.js.map +1 -0
- package/dist/core/_types_/types.d.ts +8 -0
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/{token/token-core.d.ts → auth/jwt-validation.d.ts} +2 -2
- package/dist/core/auth/jwt-validation.d.ts.map +1 -0
- package/dist/core/{token/token-core.js → auth/jwt-validation.js} +4 -4
- package/dist/core/auth/jwt-validation.js.map +1 -0
- package/dist/core/auth/middleware.d.ts +47 -0
- package/dist/core/auth/middleware.d.ts.map +1 -0
- package/dist/core/{token/token-auth.js → auth/middleware.js} +114 -2
- package/dist/core/auth/middleware.js.map +1 -0
- package/dist/core/auth/multi-auth.d.ts +27 -0
- package/dist/core/auth/multi-auth.d.ts.map +1 -0
- package/dist/core/auth/multi-auth.js +300 -0
- package/dist/core/auth/multi-auth.js.map +1 -0
- package/dist/core/auth/token-generator/html.d.ts.map +1 -0
- package/dist/core/{token/gen-token-app → auth/token-generator}/html.js +2 -2
- package/dist/core/auth/token-generator/html.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm-auth-options.d.ts.map +1 -0
- package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-auth-options.js +1 -1
- package/dist/core/auth/token-generator/ntlm-auth-options.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm-domain-config.d.ts.map +1 -0
- package/dist/core/auth/token-generator/ntlm-domain-config.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm-integration.d.ts.map +1 -0
- package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-integration.js +4 -4
- package/dist/core/auth/token-generator/ntlm-integration.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm-session-storage.d.ts.map +1 -0
- package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-session-storage.js +1 -1
- package/dist/core/auth/token-generator/ntlm-session-storage.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm-templates.d.ts.map +1 -0
- package/dist/core/auth/token-generator/ntlm-templates.js.map +1 -0
- package/dist/core/{token/gen-token-app/gen-token-server.d.ts → auth/token-generator/server.d.ts} +1 -1
- package/dist/core/auth/token-generator/server.d.ts.map +1 -0
- package/dist/core/{token/gen-token-app/gen-token-server.js → auth/token-generator/server.js} +3 -3
- package/dist/core/auth/token-generator/server.js.map +1 -0
- package/dist/core/auth/types.d.ts +35 -0
- package/dist/core/auth/types.d.ts.map +1 -0
- package/dist/core/auth/types.js +14 -0
- package/dist/core/auth/types.js.map +1 -0
- package/dist/core/cache/cache.d.ts.map +1 -1
- package/dist/core/cache/cache.js +3 -2
- package/dist/core/cache/cache.js.map +1 -1
- package/dist/core/index.d.ts +5 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/web/server-http.js +1 -1
- package/dist/core/web/server-http.js.map +1 -1
- package/package.json +2 -2
- package/dist/core/token/gen-token-app/gen-token-server.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/gen-token-server.js.map +0 -1
- package/dist/core/token/gen-token-app/html.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/html.js.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-auth-options.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-auth-options.js.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-domain-config.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-domain-config.js.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-integration.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-integration.js.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-session-storage.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-session-storage.js.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-templates.d.ts.map +0 -1
- package/dist/core/token/gen-token-app/ntlm-templates.js.map +0 -1
- package/dist/core/token/i-token.d.ts +0 -13
- package/dist/core/token/i-token.d.ts.map +0 -1
- package/dist/core/token/i-token.js +0 -2
- package/dist/core/token/i-token.js.map +0 -1
- package/dist/core/token/token-auth.d.ts +0 -17
- package/dist/core/token/token-auth.d.ts.map +0 -1
- package/dist/core/token/token-auth.js.map +0 -1
- package/dist/core/token/token-core.d.ts.map +0 -1
- package/dist/core/token/token-core.js.map +0 -1
- /package/dist/core/{token/gen-token-app → auth/token-generator}/html.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-auth-options.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-domain-config.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-domain-config.js +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-integration.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-session-storage.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-templates.d.ts +0 -0
- /package/dist/core/{token/gen-token-app → auth/token-generator}/ntlm-templates.js +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// noinspection UnnecessaryLocalVariableJS
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example: Custom Basic Authentication Implementation
|
|
5
|
+
*
|
|
6
|
+
* This example shows how to implement custom basic authentication
|
|
7
|
+
* validation with fa-mcp-sdk multi-authentication system.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import { McpServerData, CustomBasicAuthValidator, initMcpServer } from 'fa-mcp-sdk';
|
|
12
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
+
|
|
14
|
+
// ========================================================================
|
|
15
|
+
// EXAMPLE 1: Database-backed Authentication
|
|
16
|
+
// ========================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom validator using database lookup
|
|
20
|
+
*/
|
|
21
|
+
const databaseBasicAuthValidator: CustomBasicAuthValidator = async (username: string, password: string): Promise<boolean> => {
|
|
22
|
+
// Example: Check credentials against a database
|
|
23
|
+
try {
|
|
24
|
+
// This would be your actual database query
|
|
25
|
+
const user = await getUserFromDatabase(username);
|
|
26
|
+
|
|
27
|
+
if (!user) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Example: Compare hashed password
|
|
32
|
+
const isValidPassword = await comparePassword(password, user.hashedPassword);
|
|
33
|
+
return isValidPassword;
|
|
34
|
+
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Database authentication error:', error);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ========================================================================
|
|
42
|
+
// EXAMPLE 2: LDAP/Active Directory Authentication
|
|
43
|
+
// ========================================================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Custom validator using LDAP/AD
|
|
47
|
+
*/
|
|
48
|
+
const ldapBasicAuthValidator: CustomBasicAuthValidator = async (username: string, password: string): Promise<boolean> => {
|
|
49
|
+
try {
|
|
50
|
+
// Example LDAP authentication
|
|
51
|
+
const ldapResult = await authenticateWithLDAP(username, password);
|
|
52
|
+
return ldapResult.success;
|
|
53
|
+
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('LDAP authentication error:', error);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// ========================================================================
|
|
61
|
+
// EXAMPLE 3: External API Authentication
|
|
62
|
+
// ========================================================================
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Custom validator using external authentication service
|
|
66
|
+
*/
|
|
67
|
+
const externalApiAuthValidator: CustomBasicAuthValidator = async (username: string, password: string): Promise<boolean> => {
|
|
68
|
+
try {
|
|
69
|
+
const response = await fetch('https://auth.example.com/validate', {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify({ username, password }),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result: any = await response.json();
|
|
80
|
+
return result.valid === true;
|
|
81
|
+
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('External API authentication error:', error);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ========================================================================
|
|
89
|
+
// EXAMPLE 4: Multi-factor Authentication
|
|
90
|
+
// ========================================================================
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Custom validator with multi-factor authentication
|
|
94
|
+
*/
|
|
95
|
+
const mfaBasicAuthValidator: CustomBasicAuthValidator = async (username: string, password: string): Promise<boolean> => {
|
|
96
|
+
try {
|
|
97
|
+
// Password format: "actualPassword:mfaToken"
|
|
98
|
+
const [actualPassword, mfaToken] = password.split(':');
|
|
99
|
+
|
|
100
|
+
if (!actualPassword || !mfaToken) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Validate base credentials
|
|
105
|
+
const user = await getUserFromDatabase(username);
|
|
106
|
+
if (!user || !(await comparePassword(actualPassword, user.hashedPassword))) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Validate MFA token
|
|
111
|
+
const mfaValid = await validateMFAToken(username, mfaToken);
|
|
112
|
+
return mfaValid;
|
|
113
|
+
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('MFA authentication error:', error);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// ========================================================================
|
|
121
|
+
// MCP SERVER INITIALIZATION WITH CUSTOM AUTH
|
|
122
|
+
// ========================================================================
|
|
123
|
+
|
|
124
|
+
const tools: Tool[] = [
|
|
125
|
+
{
|
|
126
|
+
name: 'example-tool',
|
|
127
|
+
description: 'An example tool',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
message: { type: 'string' },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const toolHandler = async (params: { name: string; arguments?: any }) => {
|
|
138
|
+
return { content: [{ type: 'text', text: `Tool ${params.name} executed` }] };
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const mcpServerData: McpServerData = {
|
|
142
|
+
tools,
|
|
143
|
+
toolHandler,
|
|
144
|
+
agentBrief: 'Example MCP Server with Custom Basic Auth',
|
|
145
|
+
agentPrompt: 'This server demonstrates custom basic authentication.',
|
|
146
|
+
|
|
147
|
+
// Custom basic auth validator
|
|
148
|
+
// @ts-ignore
|
|
149
|
+
customBasicAuthValidator: databaseBasicAuthValidator, // or any of the other validators
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// ========================================================================
|
|
153
|
+
// MOCK FUNCTIONS (Replace with your actual implementations)
|
|
154
|
+
// ========================================================================
|
|
155
|
+
|
|
156
|
+
async function getUserFromDatabase (username: string): Promise<{ hashedPassword: string } | null> {
|
|
157
|
+
// Mock implementation - replace with your database query
|
|
158
|
+
const mockUsers = {
|
|
159
|
+
'admin': { hashedPassword: 'hashed_admin_password' },
|
|
160
|
+
'user': { hashedPassword: 'hashed_user_password' },
|
|
161
|
+
};
|
|
162
|
+
return mockUsers[username as keyof typeof mockUsers] || null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function comparePassword (plaintext: string, hashed: string): Promise<boolean> {
|
|
166
|
+
// Mock implementation - replace with proper password hashing library (e.g., bcrypt)
|
|
167
|
+
return `hashed_${plaintext}_password` === hashed;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function authenticateWithLDAP (username: string, password: string): Promise<{ success: boolean }> {
|
|
171
|
+
// Mock implementation - replace with actual LDAP client
|
|
172
|
+
return { success: username === 'ldapuser' && password === 'ldappassword' };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function validateMFAToken (username: string, token: string): Promise<boolean> {
|
|
176
|
+
// Mock implementation - replace with actual MFA validation
|
|
177
|
+
return token === '123456'; // Mock 6-digit MFA token
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ========================================================================
|
|
181
|
+
// START THE SERVER
|
|
182
|
+
// ========================================================================
|
|
183
|
+
|
|
184
|
+
// Initialize and start the MCP server with custom basic authentication
|
|
185
|
+
initMcpServer(mcpServerData).catch(console.error);
|
|
186
|
+
|
|
187
|
+
// ========================================================================
|
|
188
|
+
// CONFIGURATION EXAMPLE (config/default.yaml)
|
|
189
|
+
// ========================================================================
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
webServer:
|
|
193
|
+
auth:
|
|
194
|
+
enabled: true
|
|
195
|
+
basic:
|
|
196
|
+
type: 'basic'
|
|
197
|
+
# When using custom validator, username/password can be anything or even omitted
|
|
198
|
+
# The custom validator function will handle the actual authentication
|
|
199
|
+
username: 'placeholder'
|
|
200
|
+
password: 'placeholder'
|
|
201
|
+
# Other auth types can be configured alongside custom basic auth
|
|
202
|
+
jwtToken:
|
|
203
|
+
encryptKey: 'your-secret-key'
|
|
204
|
+
checkMCPName: true
|
|
205
|
+
permanentServerTokens:
|
|
206
|
+
- 'server-token-1'
|
|
207
|
+
- 'server-token-2'
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
// ========================================================================
|
|
211
|
+
// USAGE EXAMPLES
|
|
212
|
+
// ========================================================================
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
1. Using curl with custom basic auth:
|
|
216
|
+
|
|
217
|
+
curl -X POST http://localhost:3000/mcp \
|
|
218
|
+
-H "Content-Type: application/json" \
|
|
219
|
+
-H "Authorization: Basic $(echo -n 'admin:adminpassword' | base64)" \
|
|
220
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
221
|
+
|
|
222
|
+
2. With MFA (if using mfaBasicAuthValidator):
|
|
223
|
+
|
|
224
|
+
curl -X POST http://localhost:3000/mcp \
|
|
225
|
+
-H "Content-Type: application/json" \
|
|
226
|
+
-H "Authorization: Basic $(echo -n 'admin:adminpassword:123456' | base64)" \
|
|
227
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
228
|
+
|
|
229
|
+
3. JavaScript client example:
|
|
230
|
+
|
|
231
|
+
const credentials = btoa('admin:adminpassword');
|
|
232
|
+
const response = await fetch('http://localhost:3000/mcp', {
|
|
233
|
+
method: 'POST',
|
|
234
|
+
headers: {
|
|
235
|
+
'Content-Type': 'application/json',
|
|
236
|
+
'Authorization': `Basic ${credentials}`
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify({
|
|
239
|
+
jsonrpc: '2.0',
|
|
240
|
+
id: 1,
|
|
241
|
+
method: 'tools/list',
|
|
242
|
+
params: {}
|
|
243
|
+
})
|
|
244
|
+
});
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
export {
|
|
248
|
+
databaseBasicAuthValidator,
|
|
249
|
+
ldapBasicAuthValidator,
|
|
250
|
+
externalApiAuthValidator,
|
|
251
|
+
mfaBasicAuthValidator,
|
|
252
|
+
};
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Примеры использования системы мультиаутентификации fa-mcp-sdk
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import express from 'express';
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
import { appConfig, enhancedAuthTokenMW, createConfigurableAuthMiddleware, getMultiAuthError, getAuthInfo, checkMultiAuth, detectAuthConfiguration, logAuthConfiguration } from 'fa-mcp-sdk';
|
|
8
|
+
|
|
9
|
+
// ========================================================================
|
|
10
|
+
// ПРИМЕР 1: ПРОСТАЯ ЗАМЕНА MIDDLEWARE
|
|
11
|
+
// ========================================================================
|
|
12
|
+
|
|
13
|
+
const app = express();
|
|
14
|
+
|
|
15
|
+
// Вместо старого authTokenMW используем enhancedAuthTokenMW
|
|
16
|
+
app.use('/api', enhancedAuthTokenMW);
|
|
17
|
+
|
|
18
|
+
app.get('/api/protected', (req, res) => {
|
|
19
|
+
const authInfo = (req as any).authInfo;
|
|
20
|
+
res.json({
|
|
21
|
+
message: 'Access granted',
|
|
22
|
+
authType: authInfo?.authType,
|
|
23
|
+
username: authInfo?.username,
|
|
24
|
+
tokenType: authInfo?.tokenType,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ========================================================================
|
|
29
|
+
// ПРИМЕР 2: КОНФИГУРИРУЕМЫЙ MIDDLEWARE
|
|
30
|
+
// ========================================================================
|
|
31
|
+
|
|
32
|
+
// Middleware с логированием конфигурации при запуске
|
|
33
|
+
const authWithLogging = createConfigurableAuthMiddleware({
|
|
34
|
+
logConfiguration: true,
|
|
35
|
+
forceMultiAuth: false, // Автоматически определяет нужна ли мультиаут
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
app.use('/api/v2', authWithLogging);
|
|
39
|
+
|
|
40
|
+
// ========================================================================
|
|
41
|
+
// ПРИМЕР 3: КАСТОМНАЯ ЛОГИКА АУТЕНТИФИКАЦИИ
|
|
42
|
+
// ========================================================================
|
|
43
|
+
|
|
44
|
+
app.use('/api/custom', async (req, res, next) => {
|
|
45
|
+
// Публичные эндпоинты
|
|
46
|
+
if (req.path.startsWith('/api/custom/public')) {
|
|
47
|
+
return next();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Для админских эндпоинтов требуем только permanent tokens
|
|
51
|
+
if (req.path.startsWith('/api/custom/admin')) {
|
|
52
|
+
const token = (req.headers.authorization || '').replace(/^Bearer */, '');
|
|
53
|
+
const auth = appConfig.webServer.auth;
|
|
54
|
+
|
|
55
|
+
if (auth.permanentServerTokens.includes(token)) {
|
|
56
|
+
return next();
|
|
57
|
+
} else {
|
|
58
|
+
return res.status(403).json({ error: 'Admin access required' });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Для остальных используем полную мультиаутентификацию
|
|
64
|
+
const authError = await getMultiAuthError(req);
|
|
65
|
+
if (authError) {
|
|
66
|
+
res.status(authError.code).send(authError.message);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
next();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
res.status(500).send('Authentication error');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ========================================================================
|
|
77
|
+
// ПРИМЕР 4: РОУТЕР С РАЗНЫМИ УРОВНЯМИ ДОСТУПА
|
|
78
|
+
// ========================================================================
|
|
79
|
+
|
|
80
|
+
const apiRouter = express.Router();
|
|
81
|
+
|
|
82
|
+
// Публичные роуты - без аутентификации
|
|
83
|
+
apiRouter.get('/health', (req, res) => {
|
|
84
|
+
res.json({ status: 'ok' });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
apiRouter.get('/info', (req, res) => {
|
|
88
|
+
const authInfo = getAuthInfo();
|
|
89
|
+
res.json({
|
|
90
|
+
authEnabled: authInfo.enabled,
|
|
91
|
+
configuredTypes: authInfo.configured,
|
|
92
|
+
validTypes: authInfo.valid,
|
|
93
|
+
usingMultiAuth: authInfo.usingMultiAuth,
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Защищенные роуты - с мультиаутентификацией
|
|
98
|
+
apiRouter.use('/protected', enhancedAuthTokenMW);
|
|
99
|
+
|
|
100
|
+
apiRouter.get('/protected/profile', (req, res) => {
|
|
101
|
+
const authInfo = (req as any).authInfo;
|
|
102
|
+
res.json({
|
|
103
|
+
profile: {
|
|
104
|
+
authType: authInfo.authType,
|
|
105
|
+
username: authInfo.username || 'anonymous',
|
|
106
|
+
permissions: getPermissionsForAuthType(authInfo.authType),
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
apiRouter.get('/protected/data', (req, res) => {
|
|
112
|
+
const authInfo = (req as any).authInfo;
|
|
113
|
+
|
|
114
|
+
// Разные данные в зависимости от типа аутентификации
|
|
115
|
+
let data;
|
|
116
|
+
switch (authInfo.authType) {
|
|
117
|
+
case 'permanentServerTokens':
|
|
118
|
+
data = { level: 'server', access: 'full' };
|
|
119
|
+
break;
|
|
120
|
+
case 'oauth2':
|
|
121
|
+
data = { level: 'user', access: 'scoped', scopes: authInfo.payload?.scope };
|
|
122
|
+
break;
|
|
123
|
+
case 'basic':
|
|
124
|
+
data = { level: 'basic', access: 'limited', username: authInfo.username };
|
|
125
|
+
break;
|
|
126
|
+
case 'pat':
|
|
127
|
+
data = { level: 'api', access: 'token-based' };
|
|
128
|
+
break;
|
|
129
|
+
case 'jwtToken':
|
|
130
|
+
data = { level: 'jwt', access: 'custom', payload: authInfo.payload };
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
data = { level: 'unknown', access: 'none' };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
res.json({ data, authInfo: authInfo.authType });
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
app.use('/api/v3', apiRouter);
|
|
140
|
+
|
|
141
|
+
// ========================================================================
|
|
142
|
+
// ПРИМЕР 5: ПРОГРАММНОЕ ТЕСТИРОВАНИЕ ТОКЕНОВ
|
|
143
|
+
// ========================================================================
|
|
144
|
+
|
|
145
|
+
app.post('/api/test-token', async (req, res) => {
|
|
146
|
+
const { token } = req.body;
|
|
147
|
+
|
|
148
|
+
if (!token) {
|
|
149
|
+
return res.status(400).json({ error: 'Token required' });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const authConfig = appConfig.webServer.auth;
|
|
154
|
+
const result = await checkMultiAuth(token, authConfig);
|
|
155
|
+
|
|
156
|
+
return res.json({
|
|
157
|
+
valid: result.success,
|
|
158
|
+
authType: result.authType,
|
|
159
|
+
tokenType: result.tokenType,
|
|
160
|
+
error: result.error,
|
|
161
|
+
username: result.username,
|
|
162
|
+
hasPayload: !!result.payload,
|
|
163
|
+
});
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return res.status(500).json({ error: 'Authentication test failed' });
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// ========================================================================
|
|
170
|
+
// ПРИМЕР 6: MIDDLEWARE ДЛЯ РАЗНЫХ ТИПОВ API
|
|
171
|
+
// ========================================================================
|
|
172
|
+
|
|
173
|
+
// REST API - требует любую валидную аутентификацию
|
|
174
|
+
app.use('/rest', enhancedAuthTokenMW);
|
|
175
|
+
|
|
176
|
+
// GraphQL API - требует user-level аутентификацию (не server tokens)
|
|
177
|
+
app.use('/graphql', async (req, res, next) => {
|
|
178
|
+
try {
|
|
179
|
+
const authError = await getMultiAuthError(req);
|
|
180
|
+
if (authError) {
|
|
181
|
+
return res.status(authError.code).send(authError.message);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const authInfo = (req as any).authInfo;
|
|
185
|
+
if (authInfo.authType === 'permanentServerTokens') {
|
|
186
|
+
return res.status(403).json({
|
|
187
|
+
error: 'GraphQL API requires user authentication, server tokens not allowed',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return next();
|
|
192
|
+
} catch (error) {
|
|
193
|
+
return res.status(500).send('Authentication error');
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// WebSocket API - только JWT токены (для real-time connections)
|
|
198
|
+
app.use('/ws', async (req, res, next) => {
|
|
199
|
+
try {
|
|
200
|
+
const authError = await getMultiAuthError(req);
|
|
201
|
+
if (authError) {
|
|
202
|
+
return res.status(authError.code).send(authError.message);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const authInfo = (req as any).authInfo;
|
|
206
|
+
if (authInfo.authType !== 'jwtToken' && authInfo.authType !== 'oauth2') {
|
|
207
|
+
return res.status(403).json({
|
|
208
|
+
error: 'WebSocket API requires JWT or OAuth2 tokens for session management',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return next();
|
|
213
|
+
} catch {
|
|
214
|
+
return res.status(500).send('Authentication error');
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ========================================================================
|
|
219
|
+
// УТИЛИТНЫЕ ФУНКЦИИ
|
|
220
|
+
// ========================================================================
|
|
221
|
+
|
|
222
|
+
export function getPermissionsForAuthType (authType: string): string[] {
|
|
223
|
+
const permissions: Record<string, string[]> = {
|
|
224
|
+
'permanentServerTokens': ['read', 'write', 'admin', 'server'],
|
|
225
|
+
'oauth2': ['read', 'write', 'user'],
|
|
226
|
+
'jwtToken': ['read', 'write', 'session'],
|
|
227
|
+
'pat': ['read', 'write', 'api'],
|
|
228
|
+
'basic': ['read', 'basic'],
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
return permissions[authType] || ['read'];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ========================================================================
|
|
235
|
+
// ПРИМЕР 7: ИНИЦИАЛИЗАЦИЯ С ДИАГНОСТИКОЙ
|
|
236
|
+
// ========================================================================
|
|
237
|
+
|
|
238
|
+
export function initializeAuthSystem () {
|
|
239
|
+
const authConfig = appConfig.webServer.auth;
|
|
240
|
+
|
|
241
|
+
console.log('🔐 Initializing Multi-Authentication System...');
|
|
242
|
+
|
|
243
|
+
// Диагностика конфигурации
|
|
244
|
+
const detection = detectAuthConfiguration(authConfig);
|
|
245
|
+
|
|
246
|
+
console.log('📊 Auth Configuration:');
|
|
247
|
+
console.log(` Enabled: ${authConfig.enabled}`);
|
|
248
|
+
console.log(` Configured: ${detection.configured.join(', ')}`);
|
|
249
|
+
console.log(` Valid: ${detection.valid.join(', ')}`);
|
|
250
|
+
|
|
251
|
+
if (Object.keys(detection.errors).length > 0) {
|
|
252
|
+
console.warn('⚠️ Configuration Issues:');
|
|
253
|
+
Object.entries(detection.errors).forEach(([type, errors]) => {
|
|
254
|
+
console.warn(` ${type}: ${(errors as string[]).join(', ')}`);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Логирование для отладки
|
|
259
|
+
logAuthConfiguration(authConfig);
|
|
260
|
+
|
|
261
|
+
console.log('✅ Multi-Authentication System initialized successfully');
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
configured: detection.configured,
|
|
265
|
+
valid: detection.valid,
|
|
266
|
+
errors: detection.errors,
|
|
267
|
+
usingMultiAuth: !!(authConfig.pat || authConfig.basic || authConfig.oauth2),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ========================================================================
|
|
272
|
+
// ПРИМЕР 8: ТЕСТИРОВАНИЕ КОНФИГУРАЦИИ
|
|
273
|
+
// ========================================================================
|
|
274
|
+
|
|
275
|
+
export async function testAuthConfiguration () {
|
|
276
|
+
const authConfig = appConfig.webServer.auth;
|
|
277
|
+
|
|
278
|
+
console.log('🧪 Testing Authentication Configuration...');
|
|
279
|
+
|
|
280
|
+
const testCases = [
|
|
281
|
+
// Тест permanent token
|
|
282
|
+
{
|
|
283
|
+
name: 'Permanent Server Token',
|
|
284
|
+
token: authConfig.permanentServerTokens[0],
|
|
285
|
+
expectedType: 'permanentServerTokens',
|
|
286
|
+
},
|
|
287
|
+
// Тест PAT
|
|
288
|
+
{
|
|
289
|
+
name: 'Personal Access Token',
|
|
290
|
+
token: authConfig.pat,
|
|
291
|
+
expectedType: 'pat',
|
|
292
|
+
},
|
|
293
|
+
// Тест basic auth
|
|
294
|
+
{
|
|
295
|
+
name: 'Basic Authentication',
|
|
296
|
+
token: authConfig.basic
|
|
297
|
+
? Buffer.from(`${authConfig.basic.username}:${authConfig.basic.password}`).toString('base64')
|
|
298
|
+
: undefined,
|
|
299
|
+
expectedType: 'basic',
|
|
300
|
+
},
|
|
301
|
+
// Тест OAuth2
|
|
302
|
+
{
|
|
303
|
+
name: 'OAuth2 Bearer Token',
|
|
304
|
+
token: authConfig.oauth2 ? `Bearer ${authConfig.oauth2.accessToken}` : undefined,
|
|
305
|
+
expectedType: 'oauth2',
|
|
306
|
+
},
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
for (const testCase of testCases) {
|
|
310
|
+
if (!testCase.token) {
|
|
311
|
+
console.log(`⏭️ Skipping ${testCase.name}: not configured`);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
const result = await checkMultiAuth(testCase.token, authConfig);
|
|
317
|
+
|
|
318
|
+
if (result.success && result.authType === testCase.expectedType) {
|
|
319
|
+
console.log(`✅ ${testCase.name}: PASSED`);
|
|
320
|
+
} else {
|
|
321
|
+
console.log(`❌ ${testCase.name}: FAILED - ${result.error || 'Unexpected auth type'}`);
|
|
322
|
+
}
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.log(`❌ ${testCase.name}: FAILED - Authentication test error`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
console.log('🧪 Authentication testing completed');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ========================================================================
|
|
332
|
+
// ЭКСПОРТ ДЛЯ ИСПОЛЬЗОВАНИЯ
|
|
333
|
+
// ========================================================================
|