gpt4 book ai didi

java - Android 上的 Web CAS 身份验证

转载 作者:太空宇宙 更新时间:2023-11-03 13:25:22 28 4
gpt4 key购买 nike

我正在尝试通过 Android 登录 CAS 系统,但我不确定如何处理。

This stackoverflow 链接谈到了类似的事情,但我无法理解问题的解决方案。我以前没有身份验证协议(protocol)和 HTTP 方面的经验。我将不胜感激任何帮助!

编辑:我在 GitHub 上找到了适用于 Android 的 CAS 客户端,我尝试使用它来查看我是否可以正确进行身份验证。不幸的是,我仍然有问题。当我执行 login() 命令时,出现以下错误:

01-20 16:47:19.322: D/CASCLIENT(22682): Ready to get LT from https://www.purdue.edu/apps/account/cas/login?service=http://watcher.rcac.purdue.edu/nagios
01-20 16:47:21.825: D/CASCLIENT(22682): Response = HTTP/1.1 200 OK
01-20 16:47:21.875: D/CASCLIENT(22682): LT=LT-137794-1UkrL1jXJGPMZfuuVDn4RXbcQ3kfCQ
01-20 16:47:21.875: D/CASCLIENT(22682): POST https://www.purdue.edu/apps/account/cas/login?service=http://watcher.rcac.purdue.edu/nagios
01-20 16:47:23.186: D/CASCLIENT(22682): POST RESPONSE STATUS=200 : HTTP/1.1 200 OK
01-20 16:47:23.186: I/CASCLIENT(22682): Authentication to service 'http://watcher.rcac.purdue.edu/nagios' unsuccessul for username .

这是 CAS 客户端代码:

public class CasClient
{
private static final String TAG = "CASCLIENT";
private static final String CAS_LOGIN_URL_PART = "login";
private static final String CAS_LOGOUT_URL_PART = "logout";
private static final String CAS_SERVICE_VALIDATE_URL_PART = "serviceValidate";
private static final String CAS_TICKET_BEGIN = "ticket=";
private static final String CAS_LT_BEGIN = "name=\"lt\" value=\"";
private static final String CAS_USER_BEGIN = "<cas:user>";
private static final String CAS_USER_END = "</cas:user>";

/**
* An HTTP client (browser replacement) that will interact with the CAS server.
* Usually provided by the user, as it is this client that will be "logged in" to
* the CAS server.
*/
private HttpClient httpClient;
/**
* This is the "base url", or the root URL of the CAS server that is will be
* providing authentication services. If you use <code>http://x.y.z/a/login</code> to login
* to your CAS, then the base URL is <code>http://x.y.z/a/"</code>.
*/
private String casBaseURL;

/**
* Construct a new CasClient which uses the specified HttpClient
* for its HTTP calls. If the CAS authentication is successful, it is the supplied HttpClient to
* which the acquired credentials are attached.
*
* @param httpClient The HTTP client ("browser replacement") that will
* attempt to "login" to the CAS.
* @param casBaseUrl The base URL of the CAS service to be used. If you use
* <code>http://x.y.z/a/login</code> to login to your CAS, then the base URL
* is <code>http://x.y.z/a/"</code>.
*/
public CasClient (HttpClient httpClient, String casBaseUrl)
{
this.httpClient = httpClient;
this.casBaseURL = casBaseUrl;
}

/**
* Authenticate the specified user credentials and request a service ticket for the
* specified service. If no service is specified, user credentials are checks but no
* service ticket is generated (returns null).
*
* @param serviceUrl The service to login for, yielding a service ticket that can be
* presented to the service for validation. May be null, in which case the
* user credentials are validated, but no service ticket is returned by this method.
* @param username
* @param password
* @return A valid service ticket, if the specified service URL is not null and the
* (login; password) pair is accepted by the CAS server
* @throws CasAuthenticationException if the (login; password) pair is not accepted
* by the CAS server.
* @throws CasProtocolException if there is an error communicating with the CAS server
*/
public String login (String serviceUrl, String username, String password) throws CasAuthenticationException, CasProtocolException
{
String serviceTicket = null;
// The login method simulates the posting of the CAS login form. The login form contains a unique identifier
// or "LT" that is only valid for 90s. The method getLTFromLoginForm requests the login form from the cAS
// and extracts the LT that we need. Note that the LT is _service specific_ : We need to use an identical
// serviceUrl when retrieving and posting the login form.
String lt = getLTFromLoginForm (serviceUrl);
if (lt == null)
{
Log.d (TAG, "Cannot retrieve LT from CAS. Aborting authentication for '" + username + "'");
throw new CasProtocolException ("Cannot retrieve LT from CAS. Aborting authentication for '" + username + "'");
}
else
{
// Yes, it is necessary to include the serviceUrl as part of the query string. The URL must be
// identical to that used to get the LT.
Log.d(TAG,"POST " + casBaseURL + CAS_LOGIN_URL_PART + "?service=" + serviceUrl);
HttpPost httpPost = new HttpPost (casBaseURL + CAS_LOGIN_URL_PART + "?service=" + serviceUrl);
try
{
// Add form parameters to request body
List <NameValuePair> nvps = new ArrayList <NameValuePair> ();
nvps.add(new BasicNameValuePair ("_eventId", "submit"));
nvps.add(new BasicNameValuePair ("username", username));
nvps.add(new BasicNameValuePair ("gateway", "true"));
nvps.add(new BasicNameValuePair ("password", password));
nvps.add(new BasicNameValuePair ("lt", lt));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));

// execute post method
HttpResponse response = httpClient.execute(httpPost);
Log.d (TAG, "POST RESPONSE STATUS=" + response.getStatusLine().getStatusCode() + " : " + response.getStatusLine().toString());

//TODO It would seem that when the client is already authenticated, the CAS server
// redirects transparently to the service URL!
// Success if CAS replies with a 302 HTTP status code and a Location header
// We assume that if a valid ticket is provided in the Location header, that it is also a 302 HTTP STATUS
Header headers[] = response.getHeaders("Location");
if (headers != null && headers.length > 0)
serviceTicket = extractServiceTicket (headers[0].getValue());
HttpEntity entity = response.getEntity();
entity.consumeContent();

if (serviceTicket == null)
{
Log.i (TAG, "Authentication to service '" + serviceUrl + "' unsuccessul for username '" + username + "'.");
throw new CasAuthenticationException ("Authentication to service '" + serviceUrl + "' unsuccessul for username '" + username + "'.");
}
else
Log.i (TAG, "Authentication to service '" + serviceUrl + "' successul for username '" + username + "'.");
}
catch (IOException e)
{
Log.d (TAG, "IOException trying to login : " + e.getMessage());
throw new CasProtocolException ("IOException trying to login : " + e.getMessage());
}
return serviceTicket;
}
}

/**
* Logout from the CAS. This destroys all local authentication cookies
* and any tickets stored on the server.
*
* @return <code>true</false> if the logout is acknowledged by the CAS server
*/
public boolean logout ()
{
boolean logoutSuccess = false;
HttpGet httpGet = new HttpGet (casBaseURL + CAS_LOGOUT_URL_PART);
try
{
HttpResponse response = httpClient.execute(httpGet);
logoutSuccess = (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
Log.d (TAG, response.getStatusLine().toString());
}
catch (Exception e)
{
Log.d(TAG, "Exception trying to logout : " + e.getMessage());
logoutSuccess = false;
}
return logoutSuccess;
}

/**
* Validate the specified service ticket against the specified service.
* If the ticket is valid, this will yield the clear text user name
* of the authenticated user.
*
* Note that each service ticket issued by CAS can be used exactly once
* to validate.
*
* @param serviceUrl The serviceUrl to validate against
* @param serviceTicket The service ticket (previously provided by the CAS) for the serviceUrl
* @return Clear text username of the authenticated user.
* @throws CasProtocolException if a protocol or communication error occurs
* @throws CasClientValidationException if the CAS server refuses the ticket for the service
*/
public String validate (String serviceUrl, String serviceTicket) throws CasAuthenticationException, CasProtocolException
{
HttpPost httpPost = new HttpPost (casBaseURL + CAS_SERVICE_VALIDATE_URL_PART );
Log.d(TAG, "VALIDATE : " + httpPost.getRequestLine());
String username = null;
try
{
List <NameValuePair> nvps = new ArrayList <NameValuePair> ();
nvps.add(new BasicNameValuePair ("service", serviceUrl));
nvps.add(new BasicNameValuePair ("ticket", serviceTicket));
httpPost.setEntity (new UrlEncodedFormEntity(nvps));
HttpResponse response = httpClient.execute (httpPost);
Log.d (TAG, "VALIDATE RESPONSE : " + response.getStatusLine().toString());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK)
{
Log.d (TAG,"Could not validate: " + response.getStatusLine());
throw new CasAuthenticationException("Could not validate service: " + response.getStatusLine());
}
else
{
HttpEntity entity = response.getEntity();
username = extractUser (entity.getContent());
Log.d (TAG, "VALIDATE OK YOU ARE : " + username);
entity.consumeContent();
}
}
catch (Exception e)
{
Log.d (TAG, "Could not validate: " + e.getMessage ());
throw new CasProtocolException ("Could not validate : " + e.getMessage ());
}
return username;
}

/**
* This method requests the original login form from CAS.
* This form contains an LT, an initial token that must be
* presented to CAS upon sending it an authentication request
* with credentials.
*
* If the (optional) service URL is provided, this method
* will construct the URL such that CAS will correctly authenticate
* against the specified service when a subsequent authentication request
* is sent (with the login method).
*
* @param serviceUrl
* @return The LT token if it could be extracted from the CAS response, else null.
*/
protected String getLTFromLoginForm (String serviceUrl)
{
HttpGet httpGet = new HttpGet (casBaseURL + CAS_LOGIN_URL_PART + "?service=" + serviceUrl);

String lt = null;
try
{
Log.d (TAG, "Ready to get LT from " + casBaseURL + CAS_LOGIN_URL_PART + "?service=" + serviceUrl);
HttpResponse response = httpClient.execute (httpGet);
Log.d (TAG, "Response = " + response.getStatusLine().toString());
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
{
Log.d(TAG,"Could not obtain LT token from CAS: " + response.getStatusLine().getStatusCode() + " / " + response.getStatusLine());
}
else
{
HttpEntity entity = response.getEntity();
if (entity != null) lt = extractLt (entity.getContent());
entity.consumeContent();
Log.d (TAG, "LT=" + lt);
}
}
catch (ClientProtocolException e)
{
Log.d(TAG, "Getting LT client protocol exception", e);
}
catch (IOException e)
{
Log.d(TAG, "Getting LT io exception",e);
}

return lt;
}

/**
* Helper method to extract the user name from a "service validate" call to CAS.
*
* @param data Response data.
* @return The clear text username, if it could be extracted, null otherwise.
*/
protected String extractUser (InputStream dataStream)
{
BufferedReader reader = new BufferedReader (new InputStreamReader(dataStream));
String user = null;
try
{
String line = reader.readLine();
while (user == null && line != null)
{
int start = line.indexOf (CAS_USER_BEGIN);
if (start >= 0)
{
start += CAS_USER_BEGIN.length();
int end = line.indexOf(CAS_USER_END, start);
user = line.substring (start, end);
}
line = reader.readLine();
}
}
catch (IOException e)
{
Log.d (TAG, e.getLocalizedMessage());
}
return user;
}

/**
* Helper method to extract the service ticket from a login call to CAS.
*
* @param data Response data.
* @return The service ticket, if it could be extracted, null otherwise.
*/
protected String extractServiceTicket (String data)
{
Log.i(TAG, "ST DATA: " +data);
String serviceTicket = null;
int start = data.indexOf(CAS_TICKET_BEGIN);
if (start > 0)
{
start += CAS_TICKET_BEGIN.length ();
serviceTicket = data.substring (start);
}
return serviceTicket;
}


/**
* Helper method to extract the LT from the login form received from CAS.
*
* @param data InputStream with HTTP response body.
* @return The LT, if it could be extracted, null otherwise.
*/
protected String extractLt (InputStream dataStream)
{
BufferedReader reader = new BufferedReader (new InputStreamReader(dataStream));
String token = null;
try
{
String line = reader.readLine();
while (token == null && line != null)
{
int start = line.indexOf (CAS_LT_BEGIN);
if (start >= 0)
{
start += CAS_LT_BEGIN.length();
int end = line.indexOf("\"", start);
token = line.substring (start, end);
}
line = reader.readLine();
}
}
catch (IOException e)
{
Log.d (TAG, e.getMessage());
}
return token;
}

}

这是我从中调用 CAS 客户端的 Activity 。

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HttpClient client = new DefaultHttpClient();


StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy);
CasClient c = new CasClient(client,"https://www.purdue.edu/apps/account/cas/");
try {
c.login("http://watcher.rcac.purdue.edu/nagios", "0025215948", "scholar1234");
} catch (CasAuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CasProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

}

最佳答案

CAS 身份验证的想法本身并不困难,但如果没有 HTTP 经验,实现起来可能会很复杂。它基于票据,因此当您想要在网站内进行身份验证时,您将被重定向到 CAS 站点的登录门户,您必须输入您的凭据并进行验证。如果它们不匹配,您肯定会收到错误消息,否则会生成 TGT(票证授予票证)并将其返回给您的客户。因此,每次执行需要进行身份验证的操作时,都必须获取此票并将其传递给 CAS 身份验证 servlet。票证可能会过期,在这种情况下,CAS 服务器将向您发送一张新票证,该新票证必须覆盖上一张票证,而这就是您需要出示的票证。

在此link您对 CAS 的工作原理(基本上是工作流程)有详细的解释,并且 here您有一个 Java 示例和部分实现。

关于java - Android 上的 Web CAS 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21239956/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com