From 4c86d6860d4456096f4746bf3ce227a0d16cd5a3 Mon Sep 17 00:00:00 2001 From: "Crystal.Sea" Date: Wed, 9 Sep 2020 08:06:02 +0800 Subject: [PATCH] CAS REST FIX --- .../authz/cas/endpoint/CasRestV1Endpoint.java | 124 ++++++++++++- .../maxkey/web/authorize/endpoint/Client.java | 172 ++++++++++++++++++ 2 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 maxkey-protocols/maxkey-protocol-cas/src/test/java/org/maxkey/web/authorize/endpoint/Client.java diff --git a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java index 33c38a051..2af6ca85c 100644 --- a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java +++ b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse; import org.maxkey.authn.BasicAuthentication; import org.maxkey.authn.realm.AbstractAuthenticationRealm; +import org.maxkey.authz.cas.endpoint.response.ServiceResponseBuilder; import org.maxkey.authz.cas.endpoint.ticket.CasConstants; import org.maxkey.authz.cas.endpoint.ticket.ServiceTicketImpl; import org.maxkey.authz.cas.endpoint.ticket.TicketGrantingTicketImpl; @@ -57,7 +58,7 @@ import org.springframework.web.bind.annotation.RequestParam; */ @Controller public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{ - final static Logger _logger = LoggerFactory.getLogger(CasRestV1Endpoint.class); + final static Logger _logger = LoggerFactory.getLogger(CasRestV1Endpoint.class); @Autowired protected PasswordPolicyValidator passwordPolicyValidator; @@ -73,7 +74,6 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{ public ResponseEntity casLoginRestTickets( HttpServletRequest request, HttpServletResponse response, - @RequestParam(value=CasConstants.PARAMETER.SERVICE,required=false) String casService, @RequestParam(value=CasConstants.PARAMETER.REST_USERNAME,required=true) String username, @RequestParam(value=CasConstants.PARAMETER.REST_PASSWORD,required=true) String password){ @@ -133,10 +133,10 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{ } } - @RequestMapping(value="/authz/cas/v1/tickets/{ticketGrantingTicket}", + @RequestMapping(value="/authz/cas/v1/tickets/{ticketGrantingTicket}", method=RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - public ResponseEntity requestServiceTicket( + public ResponseEntity requestServiceTicket( HttpServletRequest request, HttpServletResponse response, @PathVariable("ticketGrantingTicket") String ticketGrantingTicket, @@ -168,6 +168,46 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{ } return new ResponseEntity<>("", HttpStatus.BAD_REQUEST); } + + @RequestMapping(value="/authz/cas/v1/tickets/{ticketGrantingTicket}", + method=RequestMethod.GET) + public ResponseEntity verifyTicketGrantingTicketStatus( + @PathVariable("ticketGrantingTicket") String ticketGrantingTicket, + HttpServletRequest request, + HttpServletResponse response){ + try { + TicketGrantingTicketImpl ticketGrantingTicketImpl = + (TicketGrantingTicketImpl) ticketServices.consumeTicket(ticketGrantingTicket); + if(ticketGrantingTicketImpl != null) { + return new ResponseEntity<>("", HttpStatus.OK); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return new ResponseEntity<>("", HttpStatus.NOT_FOUND); + } + + @RequestMapping(value="/authz/cas/v1/tickets/{ticketGrantingTicket}", + method=RequestMethod.DELETE) + public ResponseEntity destroyTicketGrantingTicket( + @PathVariable("ticketGrantingTicket") String ticketGrantingTicket, + HttpServletRequest request, + HttpServletResponse response){ + try { + TicketGrantingTicketImpl ticketGrantingTicketImpl = + (TicketGrantingTicketImpl) ticketServices.consumeTicket(ticketGrantingTicket); + if(ticketGrantingTicketImpl != null) { + return new ResponseEntity<>("", HttpStatus.OK); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return new ResponseEntity<>("", HttpStatus.NOT_FOUND); + } + + @RequestMapping(value="/authz/cas/v1/users", method=RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @@ -177,8 +217,80 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{ @RequestParam(value=CasConstants.PARAMETER.SERVICE,required=false) String casService, @RequestParam(value=CasConstants.PARAMETER.REST_USERNAME,required=true) String username, @RequestParam(value=CasConstants.PARAMETER.REST_PASSWORD,required=true) String password){ - - return null; + try { + if (password == null || password.isEmpty()) { + throw new BadCredentialsException("No credentials are provided or extracted to authenticate the REST request"); + } + + AbstractAuthenticationRealm authenticationRealm = + (AbstractAuthenticationRealm) WebContext.getBean("authenticationRealm"); + UserInfo loadeduserInfo = authenticationRealm.loadUserInfo(username, ""); + if (loadeduserInfo != null) { + + authenticationRealm.passwordMatches(loadeduserInfo, password); + + passwordPolicyValidator.passwordPolicyValid(loadeduserInfo); + + WebContext.setUserInfo(loadeduserInfo); + BasicAuthentication authentication =new BasicAuthentication(); + authentication.setUsername(username); + authentication.setPassword(password); + authentication.setAuthType("basic"); + + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = + new UsernamePasswordAuthenticationToken( + authentication, + "PASSWORD", + authenticationRealm.grantAuthority(loadeduserInfo) + ); + + authentication.setAuthenticated(true); + WebContext.setAuthentication(usernamePasswordAuthenticationToken); + WebContext.setUserInfo(loadeduserInfo); + + authenticationRealm.insertLoginHistory(loadeduserInfo, "CAS", "", "", "SUCCESS"); + + TicketGrantingTicketImpl ticketGrantingTicket=new TicketGrantingTicketImpl("Random",WebContext.getAuthentication(),null); + + String ticket=ticketServices.createTicket(ticketGrantingTicket); + String location = applicationConfig.getServerPrefix()+"/authz/cas/v1/tickets/" + ticket; + HttpHeaders headers = new HttpHeaders(); + headers.add("location", location); + ServiceResponseBuilder serviceResponseBuilder=new ServiceResponseBuilder(); + serviceResponseBuilder.setFormat(CasConstants.FORMAT_TYPE.JSON); + //for user + serviceResponseBuilder.setAttribute("uid", loadeduserInfo.getId()); + serviceResponseBuilder.setAttribute("displayName",loadeduserInfo.getDisplayName()); + serviceResponseBuilder.setAttribute("firstName", loadeduserInfo.getGivenName()); + serviceResponseBuilder.setAttribute("lastname", loadeduserInfo.getFamilyName()); + serviceResponseBuilder.setAttribute("mobile", loadeduserInfo.getMobile()); + serviceResponseBuilder.setAttribute("birthday", loadeduserInfo.getBirthDate()); + serviceResponseBuilder.setAttribute("gender", loadeduserInfo.getGender()+""); + + //for work + serviceResponseBuilder.setAttribute("employeeNumber", loadeduserInfo.getEmployeeNumber()); + serviceResponseBuilder.setAttribute("title", loadeduserInfo.getJobTitle()); + serviceResponseBuilder.setAttribute("email", loadeduserInfo.getWorkEmail()); + serviceResponseBuilder.setAttribute("department", loadeduserInfo.getDepartment()); + serviceResponseBuilder.setAttribute("departmentId", loadeduserInfo.getDepartmentId()); + serviceResponseBuilder.setAttribute("workRegion",loadeduserInfo.getWorkRegion()); + + serviceResponseBuilder.success().setUser(loadeduserInfo.getUsername()); + return new ResponseEntity<>(serviceResponseBuilder.serviceResponseBuilder(), headers ,HttpStatus.OK); + + }else { + String message = WebContext.getI18nValue("login.error.username"); + _logger.debug("login user " + username + " not in this System ." + message); + throw new BadCredentialsException(WebContext.getI18nValue("login.error.username")); + } + } catch (final AuthenticationException e) { + _logger.error("BadCredentialsException ", e); + return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); + } catch (final Exception e) { + + _logger.error("Exception ", e); + return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } } } diff --git a/maxkey-protocols/maxkey-protocol-cas/src/test/java/org/maxkey/web/authorize/endpoint/Client.java b/maxkey-protocols/maxkey-protocol-cas/src/test/java/org/maxkey/web/authorize/endpoint/Client.java new file mode 100644 index 000000000..ce0b8eecf --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-cas/src/test/java/org/maxkey/web/authorize/endpoint/Client.java @@ -0,0 +1,172 @@ +package org.maxkey.web.authorize.endpoint; + +import java.io.IOException; +import java.net.URLEncoder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; + +public class Client { + + public static String getTicket(final String server, final String username, final String password, + final String service) { + notNull(server, "server must not be null"); + notNull(username, "username must not be null"); + notNull(password, "password must not be null"); + notNull(service, "service must not be null"); + + return getServiceTicket(server, getTicketGrantingTicket(server, username, password), service); + } + + /** + * 取得ST + * @param server + * @param ticketGrantingTicket + * @param service + */ + private static String getServiceTicket(final String server, final String ticketGrantingTicket, final String service) { + if (ticketGrantingTicket == null) + return null; + + final HttpClient client = new HttpClient(); + + final PostMethod post = new PostMethod(server + "/" + ticketGrantingTicket); + + post.setRequestBody(new NameValuePair[] { new NameValuePair("service", service) }); + + try { + client.executeMethod(post); + + final String response = post.getResponseBodyAsString(); + + switch (post.getStatusCode()) { + case 200: + return response; + + default: + warning("Invalid response code (" + post.getStatusCode() + ") from CAS server!"); + info("Response (1k): " + response.substring(0, Math.min(1024, response.length()))); + break; + } + } + + catch (final IOException e) { + warning(e.getMessage()); + } + + finally { + post.releaseConnection(); + } + + return null; + } + + /** + * @param server + * @param username + * @param password + */ + private static String getTicketGrantingTicket(final String server, final String username, final String password) { + final HttpClient client = new HttpClient(); + + final PostMethod post = new PostMethod(server); + + post.setRequestBody(new NameValuePair[] { new NameValuePair("username", username), + new NameValuePair("password", password) }); + + try { + client.executeMethod(post); + + final String response = post.getResponseBodyAsString(); + info("TGT="+response); + switch (post.getStatusCode()) { + case 201: { + final Matcher matcher = Pattern.compile(".*action=\".*/(.*?)\".*").matcher(response); + + if (matcher.matches()) + return matcher.group(1); + + warning("Successful ticket granting request, but no ticket found!"); + info("Response (1k): " + response.substring(0, Math.min(1024, response.length()))); + break; + } + + default: + warning("Invalid response code (" + post.getStatusCode() + ") from CAS server!"); + info("Response (1k): " + response.substring(0, Math.min(1024, response.length()))); + break; + } + } + + catch (final IOException e) { + warning(e.getMessage()); + } + + finally { + post.releaseConnection(); + } + + return null; + } + + private static void ticketValidate(String serverValidate, String serviceTicket, String service) { + notNull(serviceTicket, "paramter 'serviceTicket' is not null"); + notNull(service, "paramter 'service' is not null"); + + final HttpClient client = new HttpClient(); + GetMethod post = null; + + try { + post = new GetMethod(serverValidate+"?"+"ticket="+serviceTicket+"&service="+URLEncoder.encode(service, "UTF-8")); + client.executeMethod(post); + + final String response = post.getResponseBodyAsString(); + info(response); + switch (post.getStatusCode()) { + case 200: { + info("成功取得用户数据"); + } + default: { + + } + } + + } catch (Exception e) { + warning(e.getMessage()); + } finally { + //释放资源 + post.releaseConnection(); + } + + } + + private static void notNull(final Object object, final String message) { + if (object == null) + throw new IllegalArgumentException(message); + } + + public static void main(final String[] args) throws Exception { + final String server = "https://sso.maxkey.top/maxkey/authz/cas/v1/tickets"; + final String username = "admin"; + final String password = "maxkey"; + final String service = "http://cas.demo.maxkey.top:8080/demo-cas/"; + final String proxyValidate = "https://sso.maxkey.top/maxkey/authz/cas/p3/serviceValidate"; + + + ticketValidate(proxyValidate, getTicket(server, username, password, service), service); + + } + + private static void warning(String msg) { + System.out.println(msg); + } + + private static void info(String msg) { + System.out.println(msg); + } +} +