Java-Android上的Web CAS身份验证
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java-Android上的Web CAS身份验证,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含13480字,纯文字阅读大概需要20分钟。
内容图文
![Java-Android上的Web CAS身份验证](/upload/InfoBanner/zyjiaocheng/678/2f246d2e724046f4acedae08f287c742.jpg)
我正在尝试通过Android登录到CAS系统,但我不确定该如何处理.
This stackoverflow链接讨论的是类似的内容,但我无法理解该问题的解决方案.我没有认证协议和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客户端的活动.
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身份验证全部内容,希望文章能够帮你解决Java-Android上的Web CAS身份验证所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。