- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
各位开发人员,我正在寻找将以下 java 代码转换为 c# 的方法。我已经做了一些转换,如下所示,但我的 LtpaToken 无效。我需要在 Domino 应用程序和 C# Web API 之间创建单点登录。 Notes 通讯簿中的所有用户都将包含在 SQL Server 数据库中,但有些用户不一定包含在通讯簿中。如果 Notes 地址簿中存在用户,则所有用户都将通过 IdentityServer4 登录,将使用 CN、cookieName、cookieDomain 和 Domino Secret 生成 LTPA token 。生成的cookie将被注入(inject)到用户浏览器中。
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.http.Cookie;
import org.apache.commons.codec.binary.Base64;
/**
* Lightweight Third Party Authentication. Generates and validates ltpa tokens
* used in Domino single sign on environments. Does not work with WebSphere SSO
* tokens. You need a properties file named LtpaToken.properties which holds two
* properties.
*
* <pre>
* ) domino.secret=The base64 encoded secret found in the field LTPA_DominoSecret in the SSO configuration document.
* ) cookie.domain=The domain you want generated cookies to be from. e.g. '.domain.com' (Note the leading dot)
* </pre>
*
* @author $Author: rkelly $
* @version $Revision: 1.1 $
* @created $Date: 2003/04/07 18:22:14 $
*/
public final class LtpaToken {
private byte[] creation;
private Date creationDate;
private byte[] digest;
private byte[] expires;
private Date expiresDate;
private byte[] header;
private String ltpaToken;
private byte[] rawToken;
private byte[] user;
private String dominoSecret;
/**
* Constructor for the LtpaToken object
*
* @param token Description of the Parameter
* @param cookieName
* @param cookieDomain
* @param dominoSecret
*/
public LtpaToken(String token, String cookieName, String cookieDomain, String dominoSecret) {
init();
ltpaToken = token;
this.dominoSecret = dominoSecret;
byte[] byteArray = ltpaToken.getBytes();
rawToken = Base64.decodeBase64(byteArray);
user = new byte[(rawToken.length) - 40];
for (int i = 0; i < 4; i++) {
header[i] = rawToken[i];
}
for (int i = 4; i < 12; i++) {
creation[i - 4] = rawToken[i];
}
for (int i = 12; i < 20; i++) {
expires[i - 12] = rawToken[i];
}
for (int i = 20; i < (rawToken.length - 20); i++) {
user[i - 20] = rawToken[i];
}
for (int i = (rawToken.length - 20); i < rawToken.length; i++) {
digest[i - (rawToken.length - 20)] = rawToken[i];
}
String commonName = new String(user);
System.out.println(commonName);
creationDate = new Date(Long.parseLong(new String(creation), 16) * 1000);
expiresDate = new Date(Long.parseLong(new String(expires), 16) * 1000);
System.out.println(creationDate);
System.out.println(expiresDate);
}
/**
* Constructor for the LtpaToken object
*/
private LtpaToken() {
init();
}
public static Cookie newCookie(String sessionToken, String cookieName, String cookieDomain) {
Cookie cookie = new Cookie(cookieName, sessionToken);
cookie.setDomain(cookieDomain);
cookie.setPath("/");
cookie.setSecure(false);
cookie.setMaxAge(-1);
return cookie;
}
/**
* Gets the creationDate attribute of the LtpaToken object
*
* @return The creationDate value
*/
public Date getCreationDate() {
return creationDate;
}
/**
* Gets the expiresDate attribute of the LtpaToken object
*
* @return The expiresDate value
*/
public Date getExpiresDate() {
return expiresDate;
}
/**
* Gets the user attribute of the LtpaToken object
*
* @return The user value
*/
public String getUser() {
return new String(user);
}
/**
* Validates the SHA-1 digest of the token with the Domino secret key.
*
* @return Returns true if valid.
*/
public boolean isValid() {
boolean validDigest;
boolean validDateRange;
byte[] newDigest;
byte[] bytes = null;
Date now = new Date();
MessageDigest md = getDigest();
bytes = concatenate(bytes, header);
bytes = concatenate(bytes, creation);
bytes = concatenate(bytes, expires);
bytes = concatenate(bytes, user);
bytes = concatenate(bytes, Base64.decodeBase64(dominoSecret));
newDigest = md.digest(bytes);
validDigest = MessageDigest.isEqual(digest, newDigest);
validDateRange = now.after(creationDate) && now.before(expiresDate);
return validDateRange && validDigest;
}
/**
* String representation of LtpaToken object.
*
* @return Returns token String suitable for cookie value.
*/
@Override
public String toString() {
return ltpaToken;
}
/**
* Creates a new SHA-1 <code>MessageDigest</code> instance.
*
* @return The instance.
*/
private MessageDigest getDigest() {
try {
return MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException nsae) {
nsae.printStackTrace();
}
return null;
}
/**
* Description of the Method
*/
private void init() {
creation = new byte[8];
digest = new byte[20];
expires = new byte[8];
header = new byte[4];
}
/**
* Validates the SHA-1 digest of the token with the Domino secret key.
*
* @param ltpaToken Description of the Parameter
* @param cookieName
* @param cookieDomain
* @param serverHostname
* @param dominoSecret
* @return The valid value
*/
public static boolean isValid(String ltpaToken, String cookieName,
String cookieDomain, String serverHostname, String dominoSecret) {
LtpaToken ltpa = new LtpaToken(ltpaToken, cookieName, cookieDomain,
dominoSecret);
return ltpa.isValid();
}
/**
* Generates a new LtpaToken with given parameters.
*
* @param canonicalUser User name in canonical form. e.g. 'CN=Robert
* Kelly/OU=MIS/O=EBIMED'.
* @param tokenCreation Token creation date.
* @param tokenExpires Token expiration date.
* @param cookieName
* @param cookieDomain
* @param dominoSecret
* @return The generated token.
*/
public static LtpaToken generate(String canonicalUser, Date tokenCreation, Date tokenExpires,
String cookieName, String cookieDomain, String dominoSecret) {
LtpaToken ltpa = new LtpaToken();
Calendar calendar = Calendar.getInstance();
MessageDigest md = ltpa.getDigest();
ltpa.header = new byte[]{0, 1, 2, 3};
ltpa.user = canonicalUser.getBytes();
byte[] token = null;
calendar.setTime(tokenCreation);
ltpa.creation = Long.toHexString(calendar.getTimeInMillis() / 1000).toUpperCase().getBytes();
calendar.setTime(tokenExpires);
ltpa.expires = Long.toHexString(calendar.getTimeInMillis() / 1000).toUpperCase().getBytes();
ltpa.user = canonicalUser.getBytes();
token = concatenate(token, ltpa.header);
token = concatenate(token, ltpa.creation);
token = concatenate(token, ltpa.expires);
token = concatenate(token, ltpa.user);
md.update(token);
ltpa.digest = md.digest(Base64.decodeBase64(dominoSecret));
token = concatenate(token, ltpa.digest);
String base64encodedToken = Base64.encodeBase64String(token);
return new LtpaToken(base64encodedToken, cookieName,
cookieDomain, dominoSecret);
}
/**
* Helper method to concatenate a byte array.
*
* @param a Byte array a.
* @param b Byte array b.
* @return a + b.
*/
private static byte[] concatenate(byte[] a, byte[] b) {
if (a == null) {
return b;
} else {
byte[] bytes = new byte[a.length + b.length];
System.arraycopy(a, 0, bytes, 0, a.length);
System.arraycopy(b, 0, bytes, a.length, b.length);
return bytes;
}
}
public String getLtpaToken() {
if (ltpaToken != null) {
return ltpaToken.trim();
} else {
return null;
}
}
public void setLtpaToken(String ltpaToken) {
this.ltpaToken = ltpaToken;
}
}
我已经完成了转换,但在涉及 MessageDigest java 类 c# 等效步骤时,我似乎没有得到正确的结果。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http;
using System.Text;
using System.Security.Cryptography;
namespace Authentication.Services
{
public class LtpaToken
{
private byte[] creation;
private DateTime creationDate;
private byte[] digest;
private byte[] expires;
private DateTime expiresDate;
private byte[] header;
private string ltpaToken;
private byte[] rawToken;
private byte[] user;
private string dominoSecret;
/* complex code */
private byte[] oneByte;
private int blockSize;
private int digestLength;
byte[] buffer;
private int bufOfs;
long bytesProcessed;
private int[] W;
private int[] state;
public LtpaToken(string token, string cookieName, string cookieDomain, string dominoSecret)
{
init();
ltpaToken = token;
this.dominoSecret = dominoSecret;
byte[] DS = Convert.FromBase64String(dominoSecret);
rawToken = Convert.FromBase64String(ltpaToken); //Encoding.UTF8.GetString();
user = new byte[(rawToken.Length) - 40];
for (int i = 0; i < 4; i++)
{
header[i] = rawToken[i];
}
for (int i = 4; i < 12; i++)
{
creation[i - 4] = rawToken[i];
}
for (int i = 12; i < 20; i++)
{
expires[i - 12] = rawToken[i];
}
for (int i = 20; i < (rawToken.Length - 20); i++)
{
user[i - 20] = rawToken[i];
}
for (int i = (rawToken.Length - 20); i < rawToken.Length; i++)
{
digest[i - (rawToken.Length - 20)] = rawToken[i];
}
string sheader = System.Text.Encoding.UTF8.GetString(header);
string suser = System.Text.Encoding.UTF8.GetString(user);
string sdigest = System.Text.Encoding.UTF8.GetString(digest);
string screation = System.Text.Encoding.UTF8.GetString(creation);
string sexpires = System.Text.Encoding.UTF8.GetString(expires);
//var epoch = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
//
Console.WriteLine(screation);
long hexcreationdate = long.Parse(screation, System.Globalization.NumberStyles.HexNumber);
long hexexpirationdate = long.Parse(sexpires, System.Globalization.NumberStyles.HexNumber);
Console.WriteLine(sexpires);
//
creationDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(Convert.ToDouble(hexcreationdate * 1000)).AddHours(2);
expiresDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(Convert.ToDouble(hexexpirationdate * 1000)).AddHours(2);
}
private LtpaToken()
{
init();
}
private void init()
{
creation = new byte[8];
digest = new byte[20];
expires = new byte[8];
header = new byte[4];
}
public bool isValid(string token, string cookieName, string cookieDomain, string serverHostname, string dominoSecret)
{
LtpaToken ltpaToken = new LtpaToken(token, cookieName, cookieDomain, dominoSecret);
return ltpaToken.isValid();
}
public bool isValid()
{
bool validDigest = false;
bool validDateRange = false;
byte[] newDigest;
byte[] bytes = null;
DateTime now = DateTime.Now;
bytes = concatenate(bytes, header);
bytes = concatenate(bytes, creation);
bytes = concatenate(bytes, expires);
bytes = concatenate(bytes, user);
bytes = concatenate(bytes, Convert.FromBase64String(dominoSecret));
newDigest = getSHA1(bytes);
validDigest = digestIsEqual(newDigest);
validDateRange = dateIsInRage();
string result = System.Text.Encoding.UTF8.GetString(user);
return validDigest & validDateRange;
}
private bool digestIsEqual(byte[] newDigest)
{
bool v = newDigest.SequenceEqual(digest);
switch (v)
{
case true:
return true;
default:
return false;
}
}
public static LtpaToken generate(String canonicalUser, DateTime tokenCreation, DateTime tokenExpires,
String cookieName, String cookieDomain, String dominoSecret)
{
LtpaToken ltpa = new LtpaToken();
SHA1 md = SHA1.Create();
ltpa.header = new byte[] { 0, 1, 2, 3 };
byte[] token = null;
string strCreation = tokenCreation.ToString("yyyyMMddhhmmss");
long decValue = Convert.ToInt64(strCreation);
//Convert to HEX 1245D8F5F7C8
string screation = decValue.ToString("X");
string strExpires = tokenCreation.ToString("yyyyMMddhhmmss");
long expDecValue = Convert.ToInt64(strExpires);
//Convert to HEX 1245D8F5F7C8
string sexpires = expDecValue.ToString("X");
//string screation = tokenCreation.Ticks.ToString("X4");
//string sexpires = tokenExpires.Ticks.ToString("X4");
Console.WriteLine(screation);
ltpa.creation = Encoding.ASCII.GetBytes(screation);
ltpa.expires = Encoding.ASCII.GetBytes(sexpires);
ltpa.user = Encoding.ASCII.GetBytes(canonicalUser);
token = concatenate(token, ltpa.header);
token = concatenate(token, ltpa.creation);
token = concatenate(token, ltpa.expires);
token = concatenate(token, ltpa.user);
//Console.WriteLine(Convert.ToBase64String(token));
token = getSHA1(token);
Console.WriteLine(Convert.ToBase64String(token));
//md.ComputeHash(token);
byte[] dominoBytes = Convert.FromBase64String(dominoSecret);
ltpa.digest = md.TransformFinalBlock(Convert.FromBase64String(dominoSecret), 0, dominoBytes.Length);
token = concatenate(token, ltpa.digest);
String base64encodedToken = Convert.ToBase64String(token, 0, token.Length);
Console.WriteLine(base64encodedToken);
return ltpa;
}
public static String byte2hex(byte[] b)
{
String hs = "";
String stmp = "";
for (int n = 0; n < b.Length; n++)
{
stmp = (b[n]).ToString("X4");
if (stmp.Length == 1) hs = hs + "0" + stmp;
else
{
hs = hs + stmp;
}
}
return hs.ToUpper();
}
private bool dateIsInRage()
{
if (DateTime.Now > creationDate && DateTime.Now < expiresDate)
{
return true;
}
else
{
return false;
}
}
private static byte[] getSHA1(byte[] digest)
{
SHA1CryptoServiceProvider SHAObj = new SHA1CryptoServiceProvider();
//SHAObj.ComputeHash(ASCIIEncoding.ASCII.GetBytes(digesttext));
SHAObj.ComputeHash(digest);
byte[] newSHAObj = SHAObj.Hash;
StringBuilder sb = new StringBuilder();
foreach (byte b in newSHAObj)
{
sb.Append(b.ToString("x2"));
}
return newSHAObj;
}
private static byte[] concatenate(byte[] a, byte[] b)
{
if (a == null)
{
return b;
}
else
{
byte[] bytes = new byte[a.Length + b.Length];
Array.Copy(a, 0, bytes, 0, a.Length);
Array.Copy(b, 0, bytes, a.Length, b.Length);
return bytes;
}
}
}
}
最佳答案
按照 URL http://www-12.lotus.com/ldd/doc/tools/c/7.0/api70ug.nsf/85255d56004d2bfd85255b1800631684/ceda2cb8df47607f85256c3d005f816d?OpenDocument 中的以下信息成功解决了问题
生成 Domino 样式单点登录 token
从 Web SSO 配置的 LTPA_DominoSecret 字段读取 BASE-64 编码的 secret 数据。
从 Web SSO 配置的 LTPA_TokenExpiration 字段中读取过期间隔。
以 4 个字节的版本控制 header 信息开始。Ø 版本0为[0x00][0x01][0x02][0x03]
附加创建时间。Ø 创建时间表示为距 1970 年 1 月 1 日 12:00 GMT 的偏移量(以秒为单位)。
附加到期时间。Ø 过期时间也表示为距 1970 年 1 月 1 日 12:00 GMT 的偏移量(以秒为单位)。
附加用户名。Ø Username的格式没有限制,但建议使用LMBCS完全标记的规范名称,最大长度为MAXUSERNAME。
根据已连接的数据加上 20 字节共享 key 生成 SHA-1 哈希(20 字节)。
在用户名后附加 SHA-1 哈希值。
BASE-64 对最终标记进行编码。
关于java - Lotus Domino C# LtpaToken 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51607812/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!