![](/img/trans.png)
[英]Can Java's 'single sign-on' (use credentials from 'Credential Manager') on Windows be disabled?
[英]Use the windows credential manager in Java to get credentials for authentication into git and other services
目前我們將密碼存儲在純文本文件中,以登錄 git 和其他服務。 我們最終想擺脫它並使用 windows 憑證管理器。 我們面臨的唯一問題是我似乎沒有找到解決方案 java。
我已經看過以下主題:
但對我來說,他們沒有給我明確的答案,即使用哪個 api。 如果您能幫助我訪問這個憑證管理器,那就太棒了。
我自己正在尋找一種訪問 java 中的 Windows Credential Manager 的方法,我發現Jonas 的答案中的 Microsoft 庫提供了一種簡單的方法:
CredManagerBackedCredentialStore credentialStore = new CredManagerBackedCredentialStore();
Credential cred = credentialStore.get("MyCredentialManagerKey");
我使用的依賴項是implementation("com.microsoft.alm:auth-secure-storage:0.6.4")
,生成的Credential
object 允許我讀取用戶/密碼。 此外, CredManagerBackedCredentialStore
object 允許將條目添加到 Windows 憑據管理器中。
奶酪......不要使用那個圖書館。
A)它壞了
B)這是不必要的復雜(XML 支持的憑證 object?srsly?)
C) 它依賴於一些易受攻擊的庫。 不要那樣對你的客戶。 只是不要。 他們被困在 Java 上已經夠糟糕了。
將這兩個文件放入您的項目中,然后像這樣使用它們:
WinCred wc = new WinCred();
// Create a credential
wc.setCredential("Application Name", "Username", "Password");
// Get a credential
Credential cred = wc.getCredential("Application Name");
String username = cred.username;
String password = cred.password;
System.out.println(username);
System.out.println(password);
// Delete a credential
wc.deleteCredential("Application Name")
將此放入您的 build.gradle:
implementation('net.java.dev.jna:jna:5.11.0')
implementation('net.java.dev.jna:jna-platform:5.11.0')
第一個文件:
package wincred;
import com.sun.jna.LastErrorException;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* This class exposes functions from credential manager on Windows platform
* via JNA.
*
* Please refer to MSDN documentations for each method usage pattern
*/
interface CredAdvapi32 extends StdCallLibrary {
CredAdvapi32 INSTANCE = (CredAdvapi32) Native.load("Advapi32",
CredAdvapi32.class, W32APIOptions.UNICODE_OPTIONS);
/**
* CredRead flag
*/
int CRED_FLAGS_PROMPT_NOW = 0x0002;
int CRED_FLAGS_USERNAME_TARGET = 0x0004;
/**
* Type of Credential
*/
int CRED_TYPE_GENERIC = 1;
int CRED_TYPE_DOMAIN_PASSWORD = 2;
int CRED_TYPE_DOMAIN_CERTIFICATE = 3;
int CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4;
int CRED_TYPE_GENERIC_CERTIFICATE = 5;
int CRED_TYPE_DOMAIN_EXTENDED = 6;
int CRED_TYPE_MAXIMUM = 7; // Maximum supported cred type
int CRED_TYPE_MAXIMUM_EX = CRED_TYPE_MAXIMUM + 1000;
/**
* CredWrite flag
*/
int CRED_PRESERVE_CREDENTIAL_BLOB = 0x1;
/**
* Values of the Credential Persist field
*/
int CRED_PERSIST_NONE = 0;
int CRED_PERSIST_SESSION = 1;
int CRED_PERSIST_LOCAL_MACHINE = 2;
int CRED_PERSIST_ENTERPRISE = 3;
/**
* Credential attributes
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx
*
* typedef struct _CREDENTIAL_ATTRIBUTE {
* LPTSTR Keyword;
* DWORD Flags;
* DWORD ValueSize;
* LPBYTE Value;
* } CREDENTIAL_ATTRIBUTE, *PCREDENTIAL_ATTRIBUTE;
*
*/
class CREDENTIAL_ATTRIBUTE extends Structure {
public static class ByReference extends CREDENTIAL_ATTRIBUTE implements Structure.ByReference { }
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("Keyword",
"Flags",
"ValueSize",
"Value");
}
/**
* Name of the application-specific attribute. Names should be of the form <CompanyName>_<Name>.
* This member cannot be longer than CRED_MAX_STRING_LENGTH (256) characters.
*/
public String Keyword;
/**
* Identifies characteristics of the credential attribute. This member is reserved and should be originally
* initialized as zero and not otherwise altered to permit future enhancement.
*/
public int Flags;
/**
* Length of Value in bytes. This member cannot be larger than CRED_MAX_VALUE_SIZE (256).
*/
public int ValueSize;
/**
* Data associated with the attribute. By convention, if Value is a text string, then Value should not
* include the trailing zero character and should be in UNICODE.
*
* Credentials are expected to be portable. The application should take care to ensure that the data in
* value is portable. It is the responsibility of the application to define the byte-endian and alignment
* of the data in Value.
*/
public Pointer Value;
}
/**
* Pointer to {@See CREDENTIAL_ATTRIBUTE} struct
*/
class PCREDENTIAL_ATTRIBUTE extends Structure {
@Override
protected List<String> getFieldOrder() {
return Collections.singletonList("credential_attribute");
}
public PCREDENTIAL_ATTRIBUTE() {
super();
}
public PCREDENTIAL_ATTRIBUTE(byte[] data) {
super(new Memory(data.length));
getPointer().write(0, data, 0, data.length);
read();
}
public PCREDENTIAL_ATTRIBUTE(Pointer memory) {
super(memory);
read();
}
public Pointer credential_attribute;
}
/**
* The CREDENTIAL structure contains an individual credential
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx
*
* typedef struct _CREDENTIAL {
* DWORD Flags;
* DWORD Type;
* LPTSTR TargetName;
* LPTSTR Comment;
* FILETIME LastWritten;
* DWORD CredentialBlobSize;
* LPBYTE CredentialBlob;
* DWORD Persist;
* DWORD AttributeCount;
* PCREDENTIAL_ATTRIBUTE Attributes;
* LPTSTR TargetAlias;
* LPTSTR UserName;
* } CREDENTIAL, *PCREDENTIAL;
*/
class CREDENTIAL extends Structure {
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("Flags",
"Type",
"TargetName",
"Comment",
"LastWritten",
"CredentialBlobSize",
"CredentialBlob",
"Persist",
"AttributeCount",
"Attributes",
"TargetAlias",
"UserName");
}
public CREDENTIAL() {
super();
}
public CREDENTIAL(final int size) {
super(new Memory(size));
}
public CREDENTIAL(Pointer memory) {
super(memory);
read();
}
/**
* A bit member that identifies characteristics of the credential. Undefined bits should be initialized
* as zero and not otherwise altered to permit future enhancement.
*
* See MSDN doc for all possible flags
*/
public int Flags;
/**
* The type of the credential. This member cannot be changed after the credential is created.
*
* See MSDN doc for all possible types
*/
public int Type;
/**
* The name of the credential. The TargetName and Type members uniquely identify the credential.
* This member cannot be changed after the credential is created. Instead, the credential with the old
* name should be deleted and the credential with the new name created.
*
* See MSDN doc for additional requirement
*/
public String TargetName;
/**
* A string comment from the user that describes this credential. This member cannot be longer than
* CRED_MAX_STRING_LENGTH (256) characters.
*/
public String Comment;
/**
* The time, in Coordinated Universal Time (Greenwich Mean Time), of the last modification of the credential.
* For write operations, the value of this member is ignored.
*/
public WinBase.FILETIME LastWritten;
/**
* The size, in bytes, of the CredentialBlob member. This member cannot be larger than
* CRED_MAX_CREDENTIAL_BLOB_SIZE (512) bytes.
*/
public int CredentialBlobSize;
/**
* Secret data for the credential. The CredentialBlob member can be both read and written.
* If the Type member is CRED_TYPE_DOMAIN_PASSWORD, this member contains the plaintext Unicode password
* for UserName. The CredentialBlob and CredentialBlobSize members do not include a trailing zero character.
* Also, for CRED_TYPE_DOMAIN_PASSWORD, this member can only be read by the authentication packages.
*
* If the Type member is CRED_TYPE_DOMAIN_CERTIFICATE, this member contains the clear test
* Unicode PIN for UserName. The CredentialBlob and CredentialBlobSize members do not include a trailing
* zero character. Also, this member can only be read by the authentication packages.
*
* If the Type member is CRED_TYPE_GENERIC, this member is defined by the application.
* Credentials are expected to be portable. Applications should ensure that the data in CredentialBlob is
* portable. The application defines the byte-endian and alignment of the data in CredentialBlob.
*/
public Pointer CredentialBlob;
/**
* Defines the persistence of this credential. This member can be read and written.
*
* See MSDN doc for all possible values
*/
public int Persist;
/**
* The number of application-defined attributes to be associated with the credential. This member can be
* read and written. Its value cannot be greater than CRED_MAX_ATTRIBUTES (64).
*/
public int AttributeCount;
/**
* Application-defined attributes that are associated with the credential. This member can be read
* and written.
*/
//notTODO: Need to make this into array
public CREDENTIAL_ATTRIBUTE.ByReference Attributes;
/**
* Alias for the TargetName member. This member can be read and written. It cannot be longer than
* CRED_MAX_STRING_LENGTH (256) characters.
*
* If the credential Type is CRED_TYPE_GENERIC, this member can be non-NULL, but the credential manager
* ignores the member.
*/
public String TargetAlias;
/**
* The user name of the account used to connect to TargetName.
* If the credential Type is CRED_TYPE_DOMAIN_PASSWORD, this member can be either a DomainName\UserName
* or a UPN.
*
* If the credential Type is CRED_TYPE_DOMAIN_CERTIFICATE, this member must be a marshaled certificate
* reference created by calling CredMarshalCredential with a CertCredential.
*
* If the credential Type is CRED_TYPE_GENERIC, this member can be non-NULL, but the credential manager
* ignores the member.
*
* This member cannot be longer than CRED_MAX_USERNAME_LENGTH (513) characters.
*/
public String UserName;
}
/**
* Pointer to {@see CREDENTIAL} struct
*/
class PCREDENTIAL extends Structure {
@Override
protected List<String> getFieldOrder() {
return Collections.singletonList("credential");
}
public PCREDENTIAL() {
super();
}
public PCREDENTIAL(byte[] data) {
super(new Memory(data.length));
getPointer().write(0, data, 0, data.length);
read();
}
public PCREDENTIAL(Pointer memory) {
super(memory);
read();
}
public Pointer credential;
}
/**
* The CredRead function reads a credential from the user's credential set.
*
* The credential set used is the one associated with the logon session of the current token.
* The token must not have the user's SID disabled.
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374804(v=vs.85).aspx
*
* @param targetName
* String that contains the name of the credential to read.
* @param type
* Type of the credential to read. Type must be one of the CRED_TYPE_* defined types.
* @param flags
* Currently reserved and must be zero.
* @param pcredential
* Out - Pointer to a single allocated block buffer to return the credential.
* Any pointers contained within the buffer are pointers to locations within this single allocated block.
* The single returned buffer must be freed by calling <code>CredFree</code>.
*
* @return
* True if CredRead succeeded, false otherwise
*
* @throws LastErrorException
* GetLastError
*/
boolean CredRead(String targetName, int type, int flags, PCREDENTIAL pcredential) throws LastErrorException;
/**
* The CredWrite function creates a new credential or modifies an existing credential in the user's credential set.
* The new credential is associated with the logon session of the current token. The token must not have the
* user's security identifier (SID) disabled.
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v=vs.85).aspx
*
* @param credential
* A CREDENTIAL structure to be written.
* @param flags
* Flags that control the function's operation. The following flag is defined.
* CRED_PRESERVE_CREDENTIAL_BLOB:
* The credential BLOB from an existing credential is preserved with the same
* credential name and credential type. The CredentialBlobSize of the passed
* in Credential structure must be zero.
*
* @return
* True if CredWrite succeeded, false otherwise
*
* @throws LastErrorException
* GetLastError
*/
boolean CredWrite(CREDENTIAL credential, int flags) throws LastErrorException;
/**
* The CredDelete function deletes a credential from the user's credential set. The credential set used is the one
* associated with the logon session of the current token. The token must not have the user's SID disabled.
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374787(v=vs.85).aspx
*
* @param targetName
* String that contains the name of the credential to read.
* @param type
* Type of the credential to delete. Must be one of the CRED_TYPE_* defined types. For a list of the
* defined types, see the Type member of the CREDENTIAL structure.
* If the value of this parameter is CRED_TYPE_DOMAIN_EXTENDED, this function can delete a credential that
* specifies a user name when there are multiple credentials for the same target. The value of the TargetName
* parameter must specify the user name as Target|UserName.
* @param flags
* Reserved and must be zero.
*
* @return
* True if CredDelete succeeded, false otherwise
*
* @throws LastErrorException
* GetLastError
*/
boolean CredDelete(String targetName, int type, int flags) throws LastErrorException;
/**
* The CredFree function frees a buffer returned by any of the credentials management functions.
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796(v=vs.85).aspx
*
* @param credential
* Pointer to CREDENTIAL to be freed
*
* @throws LastErrorException
* GetLastError
*/
void CredFree(Pointer credential) throws LastErrorException;
}
另一個文件:
package wincred;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import com.sun.jna.LastErrorException;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public class WinCred implements CredAdvapi32 {
public static <T> T coalesce(final T maybeNullValue, final T nonNullValue) {
return maybeNullValue == null ? nonNullValue : maybeNullValue;
}
public class Credential {
public String target;
public String username;
public String password;
public Credential(String target, String username, String password) {
this.target = coalesce(target, "");
this.username = coalesce(username, "");
this.password = coalesce(password, "");
}
}
public Credential getCredential(String target) {
PCREDENTIAL pcredMem = new PCREDENTIAL();
try {
if (CredRead(target, 1, 0, pcredMem)) {
CREDENTIAL credMem = new CREDENTIAL(pcredMem.credential);
byte[] passwordBytes = credMem.CredentialBlob.getByteArray(0, credMem.CredentialBlobSize);
String password = new String(passwordBytes, Charset.forName("UTF-16LE"));
Credential cred = new WinCred.Credential(credMem.TargetName, credMem.UserName, password);
return cred;
} else {
int err = Native.getLastError();
throw new LastErrorException(err);
}
} finally {
CredFree(pcredMem.credential);
}
}
public boolean setCredential(String target, String userName, String password) throws UnsupportedEncodingException {
CREDENTIAL credMem = new CREDENTIAL();
credMem.Flags = 0;
credMem.TargetName = target;
credMem.Type = CRED_TYPE_GENERIC;
credMem.UserName = userName;
credMem.AttributeCount = 0;
credMem.Persist = CRED_PERSIST_ENTERPRISE;
byte[] bpassword = password.getBytes("UTF-16LE");
credMem.CredentialBlobSize = (int) bpassword.length;
credMem.CredentialBlob = getPointer(bpassword);
if (!CredWrite(credMem, 0)) {
int err = Native.getLastError();
throw new LastErrorException(err);
} else {
return true;
}
}
public boolean deleteCredential(String target) throws UnsupportedEncodingException {
if (!CredDelete(target, CRED_TYPE_GENERIC, 0)) {
int err = Native.getLastError();
throw new LastErrorException(err);
} else {
return true;
}
}
private static Pointer getPointer(byte[] array) {
Pointer p = new Memory(array.length);
p.write(0, array, 0, array.length);
return p;
}
@Override
public boolean CredRead(String targetName, int type, int flags, PCREDENTIAL pcredential) throws LastErrorException {
synchronized (INSTANCE) {
return INSTANCE.CredRead(targetName, type, flags, pcredential);
}
}
@Override
public boolean CredWrite(CREDENTIAL credential, int flags) throws LastErrorException {
synchronized (INSTANCE) {
return INSTANCE.CredWrite(credential, flags);
}
}
@Override
public boolean CredDelete(String targetName, int type, int flags) throws LastErrorException {
synchronized (INSTANCE) {
return INSTANCE.CredDelete(targetName, type, flags);
}
}
@Override
public void CredFree(Pointer credential) throws LastErrorException {
synchronized (INSTANCE) {
INSTANCE.CredFree(credential);
}
}
}
實際上,我們公司也出現了同樣的問題。 我們有一個 Java 客戶端應用程序在 windows 上運行,客戶要求提供密碼保存功能。 因此,我們為此求助於 windows 憑證管理器。 這么多的背景。
似乎沒有 java 庫,盡管可能有一個。 (順便說一句:您的第二個鏈接是 404)。
Thus the way we planned is to write java code using the java native interface with C accessing the windows credential manager. 但我找到了這個庫:
https://github.com/microsoft/vsts-authentication-library-for-java/
其中有一個 java class 用於訪問 windows 憑證管理器:
我知道這不是一個真正的答案......但我可能會有所幫助。 干杯
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.