Showing posts with label google. Show all posts
Showing posts with label google. Show all posts

04 February 2017

Spring Security with Google SignIn



It is long time again. This time I think write some article about Spring security  with Google Signing .Last week I have worked project which need to integrate spring security with google sign in. So I think this would help developers who using spring security. This diagram shows  the use case I am going to resolve.




First step is to Add Google login button to web site. For that this documentation shows how to add google login button to website. If you follow up this steps you can add this kind of button to your website.


After you sign-in using gmail account it will return google auth token to browser.


In your sign.jsp page you need to add  web form with hidden  token field.
 

1
2
3
4
<form id="custom_form"
                  action="<c:url value='j_spring_security_check' />" method='POST'>
                <input id="formToken" type='hidden' name='token'/>
 </form>

Next spring-security.xml should be configured this way.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<sec:http auto-config="true" use-expressions="true">
        <sec:intercept-url pattern="/login" access="isAnonymous()" />
        <sec:intercept-url pattern="/logout" access="isAnonymous()" />
        <sec:intercept-url pattern="/access_denied" access="isAnonymous()" />
        <sec:intercept-url pattern="/*" access="hasRole('ROLE_ADMIN')" />

        <sec:form-login login-page="/login" authentication-failure-url="/access_denied"
                        password-parameter="token"
                        default-target-url="/home"/>

        <sec:logout logout-success-url="/logout"/>

</sec:http>

<sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider ref="authenticationProvider">
        </sec:authentication-provider>
</sec:authentication-manager>


<bean class="dev.innova.util.CustomAuthenticationProvider" id="authenticationProvider"/>


Then the last part is create custom Authentication Provider to validate user google auth token.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import dev.innova.util.UserAccount;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Value("${client.id}")
    private String CLIENT_ID;

    private static final Logger logger = LogManager.getLogger(CustomAuthenticationProvider.class.getName());

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String token = (String) authentication.getCredentials();
        NetHttpTransport transport = new NetHttpTransport();
        JsonFactory mJFactory = new GsonFactory();
        boolean validUser = false;
        GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, mJFactory)
                .setAudience(Collections.singletonList(CLIENT_ID))
                .build();

        UserAccount userAccount = new UserAccount();
        try {
            GoogleIdToken idToken = verifier.verify(token);
            if (idToken != null) {
                GoogleIdToken.Payload payload = idToken.getPayload();
                String email = payload.getEmail();
                String pictureUrl = (String) payload.get("picture");
                String userId = payload.getSubject();
                boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
                String name = (String) payload.get("name");
                userAccount.setEmailAddress(email);
                userAccount.setImageUrl(pictureUrl);
                validUser = isValidUser(email);
                logger.info("User Details Name [{}]",name);
                logger.info("User Details userId [{}]",userId);
                logger.info("User Details emailVerified [{}]",emailVerified);
                logger.info("User Details Image [{}]",pictureUrl);
            } else {
                logger.info("Invalid ID token.");
            }
        }catch (IllegalArgumentException exx){
            logger.error("Failed {}", exx.getMessage());
        }catch (GeneralSecurityException e) {
            logger.error("Failed {}", e.getMessage());
        } catch (IOException e) {
            logger.error("Failed {}", e.getMessage());
        }
        if (validUser) {
            logger.info("Valid User Found");
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            Authentication auth = new UsernamePasswordAuthenticationToken(userAccount, token, grantedAuths);
            return auth;
        } else {
            throw new BadCredentialsException("Username not found.");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        boolean equals = authentication.equals(UsernamePasswordAuthenticationToken.class);
        return equals;
    }

    /**
     *  Mock Method to validate Email
     * @param email
     * @return
     */
    private boolean isValidUser(String email){
        return true;
    }

}

Then we can create Custom UserDetails to save custom data. Which will help you to save user image, extra details.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class UserAccount implements UserDetails {

    private String userId;

    private String userName;

    private String emailAddress;

    private String imageUrl;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}

And that is it.You  can login user with google account and use spring security to secure.

04 October 2015

Android Google cloud messaging Test server

Java GCM Testing Server

Today I will share how to create java Testing Application for send android GCM notifications to android client.There are lot of examples how to create android GCM client application but for testing the notification flow you need server.But I couldn't found any good example how to create java server.So I found Library for send notifications so i used that library and create simple swing application to send notification.



Sample Code

This is the code-sample which I have already pushed in to github location(https://github.com/sajith4u/android-gsm-sample).


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package dev.innova.sajith;

import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;


public class MainClass {

    public static void main(String[] args) {
        System.out.println("starting gcm-server Application");
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                init();
            }
        });

    }

    /**
     *  Send Notification to server
     * @param apiKey
     * @param registrationId
     * @param title
     * @param messagetext
     * @return
     */
    public static String send(String apiKey, String registrationId,String title,String messagetext) {
        Sender sender = new Sender(apiKey);
        Result result = null;
        Message message = new Message.Builder()
                .addData("message",messagetext)
                .addData("title", title)
                .build();
        try {
            result = sender.send(message, registrationId, 2);
            System.out.println("Result : " + result.getMessageId());
            System.out.println("Result ErrorCode : " + result.getErrorCodeName());
            System.out.println("Result : " + result.getCanonicalRegistrationId());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }

    /**
     * Initialize the Swing form
     */
    public static void init() {
        JFrame frame = new JFrame("Notification Sender");
        frame.setSize(600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        frame.add(panel);
        placeComponents(panel);

        frame.setVisible(true);
    }

    /**
     *  Add Items to Swing form
     * @param panel
     */
    private static void placeComponents(JPanel panel) {

        panel.setLayout(null);

        JLabel apiKeyLabel = new JLabel("ApiKey");
        apiKeyLabel.setBounds(50, 20, 100, 40);
        panel.add(apiKeyLabel);

       final JTextField apiKeyText = new JTextField(20);
        apiKeyText.setBounds(160, 20, 400, 40);
        panel.add(apiKeyText);

        JLabel registrationLabel = new JLabel("Registraion ID");
        registrationLabel.setBounds(50, 70, 100, 40);
        panel.add(registrationLabel);

        final JTextField registrationText = new JTextField(20);
        registrationText.setBounds(160, 70, 400, 40);
        panel.add(registrationText);

        JLabel titleLabel = new JLabel("Title :");
        titleLabel.setBounds(50, 120, 100, 40);
        panel.add(titleLabel);

        final JTextField titleText = new JTextField(20);
        titleText.setBounds(160, 120, 400, 40);
        panel.add(titleText);

        JLabel messageLabel = new JLabel("Message :");
        messageLabel.setBounds(50, 170, 100, 40);
        panel.add(messageLabel);

        final JTextField messageText = new JTextField(20);
        messageText.setBounds(160, 170, 400, 40);
        panel.add(messageText);

        JButton resetButton = new JButton("Reset");
        resetButton.setBounds(50, 220, 120, 40);
        panel.add(resetButton);

        JButton sendNotification = new JButton("Send");
        sendNotification.setBounds(250, 220, 120, 40);
        panel.add(sendNotification);

        final JLabel statusLabel = new JLabel("status :");
        statusLabel.setBounds(50, 270, 400, 100);
        panel.add(statusLabel);

        sendNotification.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusLabel.setText("");
                String message = messageText.getText();
                String apiKey = apiKeyText.getText();
                String registrationKey = registrationText.getText();
                String titleMessage = titleText.getText();
                if((registrationKey.equals("")||registrationKey.equals(null))||(apiKey.equals("")||apiKey.equals(null))||(message.equals("")||message.equals(null))){
                    statusLabel.setText("Please Fill the above three Fields");
                }else {
                    statusLabel.setText("sending message ...........");
                    String response = send(apiKey,registrationKey,titleMessage,message);
                    statusLabel.setText(response);
                }

            }
        });

        resetButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusLabel.setText("");
                messageText.setText("");
                apiKeyText.setText("");
                registrationText.setText("");
                titleText.setText("");
            }
        });

    }


}

For use this application you need API key which provided when creating application in Google could platform and registration Id.In the next post I will share simple android client application and how to test using this server.