Android를 통해 CAS 시스템에 로그인하려고하고 있는데 어떻게 접근해야할지 모르겠습니다.Android에서 웹 CAS 인증
This stackoverflow link 비슷한 것을 이야기하지만 문제의 해결책을 이해하지 못했습니다. 인증 프로토콜과 HTTP에 대한 사전 경험이 없습니다. 나는 모든 도움에 감사 할 것입니다!
EDIT : GitHub에서 안드로이드 용 CAS 클라이언트를 찾을 수 있었고 올바르게 인증 할 수 있는지 알아보기 위해 사용하려고했습니다. 불행히도 여전히 문제가 있습니다. 내가 로그인() 명령을 실행할 때 나는 다음과 같은 오류가 발생합니다 :
여기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;
}
}
설명해 주셔서 감사합니다. 로그인을 시도하고 서비스 티켓을 받으려고 시작했습니다. 그러나, 나는 그것에 대해 약간의 문제가있다. 위 코드를 게시했습니다. – AndroidDev93