@ Entity @ Table(name = "auth_user") @ Inheritance(strategy = InheritanceType.JOINED) public class AuthUser implements Serializable, UserDetails { @ Id @ Column(name = "id") @ GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ Column(name = "identification_name", length = 64, nullable = false) private String identificationName; @ Enumerated(EnumType.STRING) @ Column(name = "type", nullable = false) private AuthorityType type; @ Column(name = "binary_authorities", nullable = false) private Long binaryAuthorities; @ Column(name = "enabled", nullable = false, columnDefinition = "tinyint") private Boolean enabled; @ Transient private Set<Authority> authorities; @ OneToOne(fetch = FetchType.LAZY, orphanRemoval = true) @ Cascade({CascadeType.ALL}) @ JoinColumn(name="user_id") private User user; @ Override public Collection<? extends GrantedAuthority> getAuthorities() { authorities = EnumSet.noneOf(Authority.class); for (Authority authority : Authority.values()) if ((binaryAuthorities & (1 << authority.ordinal())) != 0) authorities.add(authority); return authorities; } public void setAuthority(Set<Authority> authorities) { binaryAuthorities = 0L; for (Authority authority : authorities) binaryAuthorities |= 1 << authority.ordinal(); } @ Override public String getPassword() { return type.name(); } @ Override public String getUsername() { return identificationName; } @ Override public boolean isAccountNonExpired() { return true; } @ Override public boolean isAccountNonLocked() { return true; } @ Override public boolean isCredentialsNonExpired() { return true; } //getters/setters }
public enum AuthorityType implements Serializable { SIMPLE, FACEBOOK, TWITTER, GOOGLE, LINKEDIN; }
public enum Authority implements GrantedAuthority { NEW_CUSTOMER, CUSTOMER, ADMINISTRATOR; @ Override public String getAuthority() { return toString(); } }
@ Entity @ Table(name = "facebook_auth_user") public class FacebookAuthUser extends AuthUser { @ Column(name = "first_name", length = 32) private String firstName; @ Column(name = "last_name", length = 32) private String lastName; @ Column(name = "email", length = 64) private String email; @ Column(name = "token", length = 128) private String token; //any number of available properties //getters/setters }
@ Entity @ Table(name = "twitter_auth_user") public class TwitterAuthUser extends AuthUser { @ Column(name = "screen_name", length = 64) private String screenName; @ Column(name = "oauth_token", length = 80) private String oauthToken; @ Column(name = "oauth_token_secret", length = 80) private String oauthTokenSecret; //any number of available properties //getters/setters }
@ Entity @ Table(name = "simple_auth_user") public class SimpleAuthUser extends AuthUser { @ Column(name = "password", length = 40, nullable = false) private String password; @ Column(name = "uuid", length = 36, nullable = false) private String uuid; @ Override public String getPassword() { return password; } //getters/setters }
@ RequestMapping(value = "/registrate/facebook", method = RequestMethod.POST) public ModelAndView facebookRegistration() throws Exception { return new ModelAndView(new RedirectView(FACEBOOK_URL + "?client_id=" + FACEBOOK_API_KEY + + "&redirect_uri=" + FACEBOOK_URL_CALLBACK_REGISTRATION + + "&scope=email,user_location&state=registration", true, true, true)); }
@ RequestMapping(value = "/callback/facebook", method = RequestMethod.GET) public class FacebookController extends ExternalController implements Constants { @ RequestMapping(value = "/registration", params = "code") public ModelAndView registrationAccessCode(@ RequestParam("code") String code, HttpServletRequest request) throws Exception { String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_REGISTRATION, FACEBOOK_API_SECRET, code}); String token = Utils.parseURLQuery(authRequest).get("access_token"); String tokenRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token}) Map<String, Json> userInfoResponse = Json.read(tokenRequest).asJsonMap(); String email = userInfoResponse.get("email").asString().toLowerCase(); String id = userInfoResponse.get("id").asString(); //verifying ... is new? is email in DB? //creating objects Customer customer = new Customer(); customer.setEmail(email); //... customerer = (Customerer) userDAO.put(customer); FacebookAuthUser user = new FacebookAuthUser(); user.setFirstName(firstName); //... user.setIdentificationName(id); user.setToken(token); user.setType(AuthenticationType.FACEBOOK); user.setEnabled(true); user.setAuthority(EnumSet.of(Authority.CUSTOMER)); user.setUser(customer); authenticationDAO.put(user); return new ModelAndView(new RedirectView("/registrate.complete", true, true, false)); } @ RequestMapping(value = "/registration", params = "error_reason") public ModelAndView registrationError(@ RequestParam("error_description") String errorDescription, HttpServletRequest request, HttpServletResponse response) { //return client to registration page with errorDescription return new ModelAndView(new RedirectView("/registrate", true, true, false)); } //will signin and signinError }
public static String sendHttpRequest(String methodName, String url, String[] names, String[] values) throws HttpException, IOException { if (names.length != values.length) return null; if (!methodName.equalsIgnoreCase("GET") && !methodName.equalsIgnoreCase("POST")) return null; HttpMethod method; if (methodName.equalsIgnoreCase("GET")) { String[] parameters = new String[names.length]; for (int i = 0; i < names.length; i++) parameters[i] = names[i] + "=" + values[i]; method = new GetMethod(url + "?" + StringUtils.join(parameters, "&")); } else { method = new PostMethod(url); for (int i = 0; i < names.length; i++) ((PostMethod) method).addParameter(names[i], values[i]); method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } new HttpClient().executeMethod(method); return getStringFromStream(method.getResponseBodyAsStream()); } public static Map<String, String> parseURLQuery(String query) { Map<String, String> result = new HashMap<String,String>(); String params[] = query.split("&"); for (String param : params) { String temp[] = param.split("="); try { result.put(temp[0], URLDecoder.decode(temp[1], "UTF-8")); } catch (UnsupportedEncodingException exception) { exception.printStackTrace(); } } return result; }
final public static String FACEBOOK_API_KEY = "XXXXXXXXXXXXXXXX"; final public static String FACEBOOK_API_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; final public static String FACEBOOK_URL = "https://www.facebook.com/dialog/oauth"; final public static String FACEBOOK_URL_ACCESS_TOKEN = "https://graph.facebook.com/oauth/access_token"; final public static String FACEBOOK_URL_ME = "https://graph.facebook.com/me"; final public static String FACEBOOK_URL_CALLBACK_REGISTRATION = SITE_ADDRESS + "/callback/facebook/registration"; final public static String FACEBOOK_URL_CALLBACK_SIGNIN = SITE_ADDRESS + "/callback/facebook/signin";
@ RequestMapping(value = "/callback/google", method = RequestMethod.GET) public class GoogleController extends ExternalController implements Constants { @ RequestMapping(value = {"/", ""}, params = "code") public ModelAndView googleProxy(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception { ... } @ RequestMapping(value = {"/", ""}, params = "error") public ModelAndView googleErrorProxy(@RequestParam("error") String error, @RequestParam("state") String state, HttpServletRequest request) throws Exception { ... } }
@ RequestMapping(value = "/registrate/twitter", params = "action", method = RequestMethod.POST) public ModelAndView twitterRegistrationJobseeker(HttpServletRequest request) throws Exception { OAuthService service = new ServiceBuilder().provider(TwitterApi.class) .apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET) .callback(TWITTER_URL_CALLBACK_REGISTRATION).build(); Token requestToken = service.getRequestToken(); request.getSession().setAttribute("twitter", service); request.getSession().setAttribute("request_token", requestToken); return new ModelAndView(new RedirectView(service.getAuthorizationUrl(requestToken), true, true, true)); }
@ RequestMapping(value = "/callback/twitter", method = RequestMethod.GET) public class TwitterController extends ExternalController implements Constants { @ RequestMapping(value = "/registration", params = "oauth_verifier") public ModelAndView registrationAccessCode(@ RequestParam("oauth_verifier") String verifier, HttpServletRequest request, HttpServletResponse response) throws Exception { OAuthService service = (OAuthService) request.getSession().getAttribute("twitter"); Token accessToken = service.getAccessToken((Token) request.getSession().getAttribute("request_token"), new Verifier(verifier)); OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS); service.signRequest(accessToken, oauthRequest); Map<String, Json> userInfoResponse = Json.read(oauthRequest.send().getBody()).asJsonMap(); String twitterId = userInfoResponse.get("id").asString(); //verifying ... Customer customer = new Customer(); customer.setFirstName((String) request.getSession().getAttribute("pageValueFirstName")); //... customer = (Customer) userDAO.put(customer); TwitterAuthUser user = new TwitterAuthUser(); user.setAuthority(EnumSet.of(Authority.CUSTOMER)); user.setIdentificationName(twitterId); //... user.setOauthToken(accessToken.getToken()); user.setOauthTokenSecret(accessToken.getSecret()); user.setType(AuthenticationType.TWITTER); user.setUser(customer); authenticationDAO.put(user); return new ModelAndView(new RedirectView("/registrate.complete", true, true, false)); } @ RequestMapping(value = "/registration", params = "denied") public ModelAndView registrationError(HttpServletRequest request) { //response does not contain the error text return new ModelAndView(new RedirectView("/registrate", true, true, false)); } //will signin and signinError }
SimpleAuthUser user = new SimpleAuthUser(); user.setAuthority(EnumSet.of(Authority.NEW_CUSTOMER)); user.setEnabled(false); user.setIdentificationName(email); user.setPassword(passwordEncoder.encodePassword(password, email)); user.setType(AuthenticationType.SIMPLE); user.setUser(customer); user.setUuid(uuid); authenticationDAO.put(user);
<security:global-method-security secured-annotations="enabled" jsr250-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="true"/> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/**" access="permitAll"/> <security:form-login login-page="/signin"/> <security:logout invalidate-session="true" logout-success-url="/" logout-url="/signout"/> <security:remember-me services-ref="rememberMeService" key="someRememberMeKey"/> </security:http> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="authenticationProvider"/> </security:authentication-manager> <bean id="authenticationProvider" class="myproject.security.CustomAuthenticationProvider"/> <bean id="rememberMeService" class="myproject.security.RememberMeService"> <property name="key" value="someRememberMeKey"/> <property name="userDetailsService" ref="userDetailsService"/> </bean> <bean id="userDetailsService" class="myproject.security.CustomUserDetailsManager"/> <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
public class CustomUserDetailsManager implements UserDetailsService { @ Resource private AuthenticationDAO authenticationDAO; @ Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return authenticationDAO.findAuthUser(username); } }
public class CustomUserAuthentication implements Authentication { private String name; private Object details; private UserDetails user; private boolean authenticated; private Collection<? extends GrantedAuthority> authorities; public CustomUserAuthentication(UserDetails user, Object details) { this.name = user.getUsername(); this.details = details; this.user = user; this.authorities = user.getAuthorities(); authenticated = true; } @ Override public String getName() { return name; } @ Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @ Override public Object getCredentials() { return user.getPassword(); } @ Override public Object getDetails() { return details; } @ Override public Object getPrincipal() { return user; } @ Override public boolean isAuthenticated() { return authenticated; } @ Override public void setAuthenticated(boolean authenticated) throws IllegalArgumentException { this.authenticated = authenticated; } }
public class CustomAuthenticationProvider implements AuthenticationProvider { @ Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // . return authentication; } @ Override public boolean supports(Class<?> authentication) { return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication); } public Authentication trust(UserDetails user) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication trustedAuthentication = new CustomUserAuthentication(user, authentication.getDetails()); authentication = authenticate(trustedAuthentication); SecurityContextHolder.getContext().setAuthentication(authentication); return authentication; } }
Class<? extends ExternalController> controller = externalControllers.get(user.getPassword()); if (controller != null && !controller.newInstance().checkAccount(user)) return null;
private Map<String, Class<? extends ExternalController>> externalControllers; public CustomRememberMeService() { externalControllers = new HashMap<String, Class<? extends ExternalController>>(){{ put(AuthenticationType.FACEBOOK.name(), FacebookController.class); put(AuthenticationType.TWITTER.name(), TwitterController.class); put(AuthenticationType.GOOGLE.name(), GoogleController.class); put(AuthenticationType.LINKEDIN.name(), LinkedinController.class); }}; }
public abstract class ExternalController { public abstract boolean checkAccount(UserDetails user) throws Exception; }
public boolean heckAccount(UserDetails user) throws Exception { FacebookAuthUser facebookUser = (FacebookAuthUser) user; String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{facebookUser.getToken()}); Map<String, Json> tokenInfoResponse = Json.read(authRequest).asJsonMap(); return tokenInfoResponse.get("error") == null && tokenInfoResponse.get("id").asString().equalsIgnoreCase(facebookUser.getIdentificationName()); }
public boolean checkAccount(UserDetails user) throws Exception { TwitterAuthUser twitterUser = (TwitterAuthUser) user; OAuthService service = new ServiceBuilder().provider(TwitterApi.class).apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET).build(); OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS); service.signRequest(new Token(twitterUser.getOauthToken(), twitterUser.getOauthTokenSecret()), oauthRequest); String response = oauthRequest.send().getBody(); Map<String, Json> info = Json.read(request).asJsonMap(); return info.get("id").asString().equalsIgnoreCase(twitterUser.getIdentificationName()); }
@ RequestMapping(value = "/signin", params = "code") public ModelAndView signInAccessCode(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception { String accessRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_SIGNIN, FACEBOOK_API_SECRET, code}); String token = Utils.parseURLQuery(accessRequest).get("access_token"); Map<String, Json> userInfoResponse = Json.read(Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token})).asJsonMap(); FacebookAuthUser user = (FacebookAuthUser) authenticationDAO.findAuthUser(userInfoResponse.get("id").asString(), AuthenticationType.FACEBOOK); if (user == null) { //- ... return new ModelAndView(new RedirectView("/signin", true, true, false)); } else { if (!token.equals(user.getToken())) { user.setToken(token); user = (FacebookAuthUser) authenticationDAO.put(user); } Authentication authentication = customAuthenticationProvider.trust(user); if (state.equalsIgnoreCase("autosignin")) customRememberMeService.onLoginSuccess(request, response, authentication); else customRememberMeService.logout(request, response, authentication); // RememberMe return new ModelAndView(new RedirectView("/signin.complete", true, true, false)); } }
Authentication authentication = customAuthenticationProvider.trust(user); if (autosignin) customRememberMeService.onLoginSuccess(request, response, authentication); else customRememberMeService.logout(request, response, authentication);
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> ... <sec:authorize access="isAuthenticated()"> <div id="userBox"> <span>Welcome, <sec:authentication property="principal.user.firstName"/>!</span> </div> </sec:authorize>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %> <%@ page import="myproject.auth.AuthUser" %> <% Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); AuthUser authUser = null; if (!(principal instanceof String)) authUser = (AuthUser) principal; %> ... <input type="text" <%= authUser == null ? "" : "disabled=\"disabled\"" %> name="your_name" value="<%= authUser == null ? "" : authUser.getUser().getFirstName()%>"/> ... <% if (authUser == null) { %> <div id="recaptcha_widget"> <div id="recaptchaContainer"> ... </div> </div> <% } %>
Source: https://habr.com/ru/post/145695/