JITAuth.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. unit JITAuth;
  2. interface
  3. uses
  4. xmldom, XMLIntf, msxmldom, XMLDoc, Classes, SysUtils, Dialogs, LoggerImport,
  5. mybean.core.objects, InterfaceCA, IdHTTP, Forms;
  6. type
  7. SHeadInfo = Record
  8. Version:String;
  9. ServiceType:String;
  10. AuthResult:String;
  11. ErrorCode:String;
  12. ErrorDesc:String;
  13. end;
  14. SBodyInfo = Record
  15. AuthMode:String;
  16. AuthResult:String;
  17. AccessControlResult:String;
  18. AttrList:TStringList;
  19. end;
  20. TJITAuth = class(TMyBeanInterfacedObject, ICAClient)
  21. private
  22. function RandomNum: string;
  23. function GetNodeAttributeValue(xmlNode:IXMLNode; strAttribute:String):String;
  24. procedure ParseHeadNode(HeadNode:IXMLNode; var HeadInfo: SHeadInfo);
  25. procedure ParseRootNode(RootNode:IXMLNode; var HeadInfo:SHeadInfo; var BodyInfo:SBodyInfo);
  26. procedure ParseBodyNode(BodyNode:IXMLNode; var BodyInfo: SBodyInfo);
  27. function GenRandom: String;
  28. procedure InitRequestHead(AIdHttp: TIdHttp);
  29. function RequestUserJsonBySubjectDN(ASubjectDN: string): string;
  30. public
  31. function Request: string; stdcall;
  32. end;
  33. implementation
  34. uses
  35. JITComVCTKLib_TLB, CAImport, Windows, StrUtils, AppCentreImport, InterfaceAppCentre;
  36. function SplitString(const Source, Ch:string): TStringList;
  37. var
  38. Temp: string;
  39. iLoop: Integer;
  40. begin
  41. Result := TStringList.Create;
  42. Temp := Source;
  43. iLoop := Pos(Ch, Source);
  44. while iLoop <> 0 do
  45. begin
  46. Result.Add(copy(temp, 0, iLoop-1));
  47. Delete(temp, 1, iLoop);
  48. iLoop := Pos(Ch, Temp);
  49. end;
  50. Result.Add(temp);
  51. end;
  52. { TJITAuth }
  53. function TJITAuth.RandomNum: string;
  54. const
  55. CHS: string = '1234567890abcdefghijklmnopqrstopqrstuvwxyz';
  56. ASIZE: Integer = 6;
  57. var
  58. iLoop: Integer;
  59. key: array[0..5] of char;
  60. begin
  61. Randomize;
  62. for iLoop := 0 to ASIZE - 1 do
  63. key[iLoop] := CHS[Random(36)];
  64. Result := string(key);
  65. end;
  66. procedure TJITAuth.InitRequestHead(AIdHttp: TIdHttp);
  67. begin
  68. AIdHttp.Request.Accept := 'text/html, */*';
  69. AIdHttp.Request.ContentType := 'text/xml';
  70. AIdHttp.AllowCookies := True;
  71. AIdHttp.ProxyParams.BasicAuthentication := False;
  72. AIdHttp.ProxyParams.ProxyPort := 0;
  73. AIdHttp.Request.ContentLength := -1;
  74. AIdHttp.Request.ContentRangeEnd := 0;
  75. AIdHttp.Request.ContentRangeStart := 0;
  76. AIdHttp.Request.ContentType := 'text/xml';
  77. AIdHttp.Request.Accept := 'text/html, */*';
  78. AIdHttp.Request.BasicAuthentication := False;
  79. AIdHttp.HTTPOptions := [hoForceEncodeParams];
  80. end;
  81. function TJITAuth.GenRandom: String;
  82. var
  83. ReponseData, HostAddr, PostMsg:String;
  84. StrStream:TStringStream;
  85. RootNode:IXMLNode;
  86. ChildNodes, BodyChildNode:IXMLNodeList;
  87. BodyNode, TempNode:IXMLNode;
  88. I,J:Integer;
  89. PostStream:TStringStream;
  90. AConfig: ICAConfig;
  91. AIdHttp: TIdHttp;
  92. AXMLDoc: TXMLDocument;
  93. begin
  94. AConfig := GetCAConfig;
  95. Result:= '';
  96. PostMsg := '<?xml version="1.0" encoding="UTF-8"?>'
  97. + '<message>'
  98. + '<head>'
  99. + '<version>1.0</version>'
  100. + '<serviceType>OriginalService</serviceType>'
  101. + '</head>'
  102. + '<body>'
  103. + '<appId>' + AConfig.GetAppID + '</appId>'
  104. + '</body>'
  105. + '</message>';
  106. PostStream:=TStringStream.Create(AnsiToUtf8(PostMsg));
  107. HostAddr := AConfig.GetURL;
  108. AIdHttp := TIdHTTP.Create(nil);
  109. InitRequestHead(AIdHttp);
  110. try
  111. ReponseData:= AIdHttp.Post(AConfig.GetURL, PostStream);
  112. except
  113. on Ex: Exception do
  114. begin
  115. ShowMessage('CA服务器可能不存在,详细错误:' + Ex.Message);
  116. FreeAndNil(AIdHttp);
  117. PostStream.Free;
  118. Exit;
  119. end;
  120. end;
  121. PostStream.Free;
  122. FreeAndNil(AIdHttp);
  123. StrStream:=TStringStream.Create(ReponseData);
  124. AXMLDoc := TXMLDocument.Create(Application);
  125. AXMLDoc.Active := True;
  126. try
  127. AXMLDoc.LoadFromStream(StrStream);
  128. RootNode := AXMLDoc.DocumentElement;
  129. ChildNodes:=RootNode.ChildNodes;
  130. for i:=0 to ChildNodes.Count -1 do begin
  131. BodyNode := ChildNodes.Get(i);
  132. if UpperCase(BodyNode.NodeName) ='BODY' then begin
  133. BodyChildNode:=BodyNode.ChildNodes;
  134. if BodyChildNode.Count<>1 then begin
  135. EXIT;
  136. end;
  137. TempNode := BodyChildNode.Get(0);
  138. Result:= TempNode.NodeValue;
  139. end;
  140. end;
  141. except
  142. on Ex: Exception do
  143. begin
  144. ShowMessage('CA返回结果解析异常:'+ Ex.Message);
  145. StrStream.Free;
  146. AXMLDoc.Free;
  147. Exit;
  148. end;
  149. end;
  150. StrStream.Free;
  151. AXMLDoc.Free;
  152. end;
  153. function TJITAuth.Request: string;
  154. var
  155. JITVCTKObj:IJITVCTK;
  156. StrRandom, StrSignData:String;
  157. lErrorCode:Integer;
  158. ReponseData:String;
  159. StrStream:TStringStream;
  160. PostStream:TStringStream;
  161. RootNode:IXMLNode;
  162. HeadInfo:SHeadInfo;
  163. BodyInfo:SBodyInfo;
  164. I, iLoop:Integer;
  165. AConfig: ICAConfig;
  166. AIdHttp: TIdHTTP;
  167. AXMLDoc: TXMLDocument;
  168. begin
  169. //////////////////////////////////////////////////////////////////////////
  170. // 1. 生成认证请求报文
  171. //////////////////////////////////////////////////////////////////////////
  172. AConfig := GetCAConfig;
  173. JITVCTKObj:=CoJITVCTK.Create;
  174. lErrorCode:=JITVCTKObj.SetCert('SC', '', '', '', AConfig.GetCaSubject, '');
  175. if lErrorCode <> 0 then Exit;
  176. StrRandom := GenRandom;
  177. if StrRandom='' then Exit;
  178. StrSignData:=JITVCTKObj.AttachSignStr('', StrRandom);
  179. if StrSignData = '' then Exit;
  180. PostStream:=TStringStream.Create('');
  181. PostStream.WriteString('<?xml version="1.0" encoding="UTF-8"?>');
  182. PostStream.WriteString('<message>');
  183. PostStream.WriteString('<head>');
  184. PostStream.WriteString('<version>1.1</version>');
  185. PostStream.WriteString('<serviceType>AuthenService</serviceType>');
  186. PostStream.WriteString('</head>');
  187. PostStream.WriteString('<body>');
  188. PostStream.WriteString('<clientInfo>');
  189. PostStream.WriteString('<clientIP>'+ '192.168.1.100' +'</clientIP>');
  190. PostStream.WriteString('</clientInfo>');
  191. PostStream.WriteString('<appId>' + AConfig.GetAppID + '</appId>');
  192. PostStream.WriteString('<authen>');
  193. PostStream.WriteString('<authCredential authMode="cert">');
  194. PostStream.WriteString('<attach>' + StrSignData + '</attach>');
  195. PostStream.WriteString('</authCredential>');
  196. PostStream.WriteString('</authen>');
  197. PostStream.WriteString('<accessControl>true</accessControl>');
  198. PostStream.WriteString('<attributes attributeType="all">');
  199. PostStream.WriteString('<attr name="' + AnsiToUtf8('身份证') + '" namespace="http://www.jit.com.cn/ums/ns/user"></attr>');
  200. {
  201. PostStream.WriteString('<attr name="X509Certificate.SubjectDN" namespace="http://www.jit.com.cn/cinas/ias/ns/saml/saml11/X.509"></attr>');
  202. PostStream.WriteString('<attr name="UMS.UserID" namespace="http://www.jit.com.cn/pmi/pms/ns/role"></attr>');
  203. PostStream.WriteString('<attr name="' + AnsiToUtf8('性别') + '" namespace="http://www.jit.com.cn/ums/ns/user"></attr>');
  204. PostStream.WriteString('<attr name="' + AnsiToUtf8('职务') + '" namespace="http://www.jit.com.cn/ums/ns/user"></attr>');
  205. PostStream.WriteString('<attr name="' + AnsiToUtf8('部门') + '" namespace="http://www.jit.com.cn/ums/ns/user"></attr>');
  206. }
  207. PostStream.WriteString('</attributes>');
  208. PostStream.WriteString('</body>');
  209. PostStream.WriteString('</message>');
  210. //////////////////////////////////////////////////////////////////////////
  211. // 2. 发送认证请求报文
  212. //////////////////////////////////////////////////////////////////////////
  213. AIdHttp := TIdHTTP.Create(nil);
  214. InitRequestHead(AIdHttp);
  215. PostStream.Position := 0;
  216. try
  217. ReponseData := AIdHttp.Post(AConfig.GetURL, PostStream);
  218. except
  219. on Ex: Exception do
  220. begin
  221. ShowMessage('CA服务器可能不存在,详细错误:' + Ex.Message);
  222. FreeAndNil(AIdHttp);
  223. PostStream.Free;
  224. Exit;
  225. end;
  226. end;
  227. PostStream.Free;
  228. FreeAndNil(AIdHttp);
  229. /////////////////////////////////////////////////////////////////////////
  230. // 3. 解析服务器响应报文
  231. //////////////////////////////////////////////////////////////////////////
  232. StrStream:=TStringStream.Create(ReponseData);
  233. AXMLDoc := TXMLDocument.Create(Application);
  234. try
  235. AXMLDoc.LoadFromStream(StrStream);
  236. RootNode := AXMLDoc.DocumentElement;
  237. ParseRootNode(RootNode, HeadInfo, BodyInfo);
  238. except
  239. on Ex: Exception do
  240. begin
  241. ShowMessage('CA返回结果解析异常:'+ Ex.Message);
  242. StrStream.Free;
  243. AXMLDoc.Free;
  244. Exit;
  245. end;
  246. end;
  247. StrStream.Free;
  248. AXMLDoc.Free;
  249. Debug('版本:'+ HeadInfo.Version, 'TJITAuth.Request');
  250. Debug('服务类型:' + HeadInfo.ServiceType, 'TJITAuth.Request');
  251. Debug('认证结果:' + HeadInfo.AuthResult, 'TJITAuth.Request');
  252. Debug('错误码:' + HeadInfo.ErrorCode, 'TJITAuth.Request');
  253. Debug('错误信息:' + HeadInfo.ErrorDesc, 'TJITAuth.Request');
  254. Debug('认证模式:' + BodyInfo.AuthMode, 'TJITAuth.Request');
  255. Debug('认证结果:' + BodyInfo.AuthResult, 'TJITAuth.Request');
  256. Debug('访问控制:' + BodyInfo.AccessControlResult, 'TJITAuth.Request');
  257. if BodyInfo.AttrList <> nil then
  258. begin
  259. try
  260. for iLoop := 0 to BodyInfo.AttrList.Count - 1 do
  261. if SameText('X509Certificate.SubjectDN', BodyInfo.AttrList[iLoop]) then
  262. begin
  263. Result := RequestUserJsonBySubjectDN(BodyInfo.AttrList[iLoop + 2]);
  264. Break;
  265. end;
  266. finally
  267. BodyInfo.AttrList.Free;
  268. end;
  269. end;
  270. end;
  271. function TJITAuth.RequestUserJsonBySubjectDN(ASubjectDN: string): string;
  272. const
  273. GETUSER_URL: string = 'http://%s:%d/api/basic/GetUserByCA?appKey=%s&appSecret=%s&ca=%s';
  274. var
  275. AItems: TStrings;
  276. iLoop, jLoop: Integer;
  277. strTmp: string;
  278. AID: string;
  279. AIdHttp: TIdHttp;
  280. AppCentreConfig: IAppCentreConfig;
  281. AURL: string;
  282. begin
  283. AItems := SplitString(ASubjectDN, ',');
  284. try
  285. for iLoop := 0 to AItems.Count - 1 do
  286. begin
  287. strTmp := Trim(AItems[iLoop]);
  288. if Pos('T=', strTmp) = 1 then
  289. begin
  290. AID := Copy(StrTmp, 3, Length(StrTmp) - 2);
  291. Break;
  292. end;
  293. end;
  294. finally
  295. FreeAndNil(AItems);
  296. end;
  297. if AID = '' then
  298. Exit;
  299. AIdHttp := TIdHttp.Create(Application);
  300. try
  301. AppCentreConfig := GetAppCentreConfig;
  302. AURL := Format(GETUSER_URL,
  303. [Utf8ToAnsi(AppCentreConfig.GetIP),
  304. AppCentreConfig.GetPort,
  305. AppCentreConfig.GetLxtAppKey,
  306. AppCentreConfig.GetLxtAppSecret,
  307. AID]);
  308. Result := Utf8ToAnsi(AIdHttp.Get(AURL));
  309. finally
  310. FreeAndNil(AIdHttp);
  311. end;
  312. end;
  313. function TJITAuth.GetNodeAttributeValue(xmlNode:IXMLNode; strAttribute:String):String;
  314. begin
  315. // xmlNode.Get
  316. end;
  317. procedure TJITAuth.ParseHeadNode(HeadNode:IXMLNode; var HeadInfo: SHeadInfo);
  318. var
  319. ChildNodes:IXMLNodeList;
  320. ChildNode:IXMLNode;
  321. I:Integer;
  322. tempValue:String;
  323. begin
  324. ChildNodes:=HeadNode.GetChildNodes();
  325. for I:=0 to ChildNodes.Count-1 do begin
  326. ChildNode:=ChildNodes.Get(i);
  327. tempValue:=ChildNode.Text;
  328. if lowercase(ChildNode.NodeName)='version' then begin
  329. HeadInfo.Version := tempValue;
  330. end else if lowercase(ChildNode.NodeName)='servicetype' then begin
  331. HeadInfo.ServiceType := tempValue;
  332. end else if lowercase(ChildNode.NodeName)='messagestate' then begin
  333. HeadInfo.AuthResult := tempValue;
  334. end else if lowercase(ChildNode.NodeName)='messagecode' then begin
  335. HeadInfo.ErrorCode := tempValue;
  336. end else if lowercase(ChildNode.NodeName)='messagedesc' then begin
  337. HeadInfo.ErrorDesc := tempValue;
  338. end;
  339. end;
  340. end;
  341. procedure TJITAuth.ParseRootNode(RootNode:IXMLNode; var HeadInfo:SHeadInfo; var BodyInfo:SBodyInfo);
  342. var
  343. ChildNodes:IXMLNodeList;
  344. ChildNode:IXMLNode;
  345. I:Integer;
  346. begin
  347. ChildNodes:=RootNode.GetChildNodes();
  348. for I:=0 to ChildNodes.Count-1 do begin
  349. ChildNode:=ChildNodes.Get(I);
  350. if UpperCase(ChildNode.NodeName)='HEAD' then begin
  351. ParseHeadNode(ChildNode, HeadInfo);
  352. end else if UpperCase(ChildNode.NodeName)='BODY' then begin
  353. ParseBodyNode(ChildNode, BodyInfo);
  354. end;
  355. end;
  356. end;
  357. procedure TJITAuth.ParseBodyNode(BodyNode:IXMLNode; var BodyInfo: SBodyInfo);
  358. var
  359. ChildNodes:IXMLNodeList;
  360. ChildNode, AttribChildNode:IXMLNode;
  361. I,J:Integer;
  362. AuthChildNodes:IXMLNodeList;
  363. AttrName, AttrNameSpace, AttrValue:String;
  364. begin
  365. ChildNodes:=BodyNode.GetChildNodes();
  366. for I:=0 to ChildNodes.Count-1 do begin
  367. ChildNode:=ChildNodes.Get(I);
  368. if lowercase(ChildNode.NodeName)='authresultset' then begin
  369. AuthChildNodes:=ChildNode.ChildNodes;
  370. for J:=0 to AuthChildNodes.Count-1 do begin
  371. AttribChildNode:=AuthChildNodes.Get(J);
  372. if lowercase(AttribChildNode.NodeName)='authresult' then begin
  373. if AttribChildNode.HasAttribute('authMode') then BodyInfo.AuthMode:=AttribChildNode.Attributes['authMode'];
  374. if AttribChildNode.HasAttribute('success') then BodyInfo.AuthResult:=AttribChildNode.Attributes['success'];
  375. end;
  376. end;
  377. end else if lowercase(ChildNode.NodeName)='accesscontrolresult' then begin
  378. BodyInfo.AccessControlResult:=ChildNode.Text;
  379. end else if lowercase(ChildNode.NodeName)='attributes' then begin
  380. AuthChildNodes:=ChildNode.ChildNodes;
  381. BodyInfo.AttrList:=TStringList.Create;
  382. for J:=0 to AuthChildNodes.Count-1 do begin
  383. AttribChildNode:=AuthChildNodes.Get(J);
  384. if lowercase(AttribChildNode.NodeName)='attr' then begin
  385. if AttribChildNode.HasAttribute('name') then AttrName:=AttribChildNode.Attributes['name'];
  386. if AttribChildNode.HasAttribute('namespace') then AttrNameSpace:=AttribChildNode.Attributes['namespace'];
  387. AttrValue:=AttribChildNode.NodeValue;
  388. BodyInfo.AttrList.Add(AttrName);
  389. BodyInfo.AttrList.Add(AttrNameSpace);
  390. BodyInfo.AttrList.Add(AttrValue);
  391. end;
  392. end;
  393. end;
  394. end;
  395. end;
  396. end.