How to authenticate a user via HTTP request?

Asked

Viewed 1,415 times

4

I’m trying to authenticate users in a forum Vbulletin by means of an application desktop using components of the package swing, the code is working but I believe that this is not the best way to do.

Logic

I used the plugin Live HTTP Headers in Firefox to find the attributes to be sent in the login form. They are:

vb_login_md5password --> A senha em MD5
vb_login_md5password_utf --> Idem ao anterior
vb_login_username --> Nome de usuário

So I created a String with these parameters, so:

String query = "do=login&url=index.php" // url de login
              + "&vb_login_md5password=" + password // a senha já em MD5
              + "&vb_login_md5password_utf=" + password // a senha novamente
              + "&s=&securitytoken=guest&vb_login_username=" + username // o nome de usuário
              + "&vb_login_password="; // !importante

Then I make a request to the login page through a HttpURLConnection and I get the code HTML from the next page - which may be an error page or the correct page if the authentication is correct. So I look for information that only a logged-in user could see, in this case it is a message written "Welcome {user name}" right at the beginning of the code HTML.

The problem...

... is that all source code HTML the page is downloaded to then be searched inside it by String "Welcome" that is found right at the beginning, ie, is downloading a lot of information beyond the necessary. I don’t believe this is the best way to do it, I’m already thinking about performance, some forums may have many sub-forums and this download of code followed by word search can be very slow.

Another problem is that, a user can change the forum language. Assuming he is using the English version (defined in the preferences in the forum) my logic would be useless because there would not be a word "Welcome" but "Welcome". So even if the username and password were correct the authentication would not occur - in the application, due to logic.

I did some research and found the Jsoup, but it serves to extract and manipulate information from an HTML code (for example, take a value by ID) and it’s not what I’m looking for.

PS: I don’t need any more user information. It’s quite simple, just know if he is a member of a particular forum, i.e, if he owns an account. Authenticated = has account, is a member. Not authenticated = not a member.


How can I authenticate a user in Vbulletin forums via an HTTP connection?

2 answers

4

The "right" way to do this would be to use a web service that returns only the necessary data. However, in a brief search on the site and in the documentation of Vbulletin I did not find a reference only this. So it remains to do as is already being done, that is, through inspection of the HTML code.

As for the language problem, it is appropriate to use a parser like Jsoup or Jericho to correctly identify the page elements and then check for any HTML tags that are common among all languages.

For example, let’s assume that the welcome message is displayed within a tag, like this:

<p id="welcome" class="welcome-title">Bem vindo, Usuário</p>

So instead of searching for the "Welcome" text, you might want to check the tag with the class .welcome-title or by the id welcome.

  • 1

    @Renan There is no possibility of you receiving a page before the server processes. Either you are accessing the wrong URL, or information is missing from the request, or it is a server bug.

1


After several attempts I found a solution using Htmlunit even with a documentation somewhat complicated I managed to authenticate a user in a Vbulletin forum. Before sharing the code, I would like to inform:

Form and submit:

Interested parties can obtain any element of the page from id or by name with the Htmlunit. In the login form both the <input> user name as the password have a name defined, the problem is that there is no way to grab the submit since it does not exist, probably the form is submitted from a Javascript file. To solve this problem I created a "button fake" and entered it into the login form (it is possible to do this with Htmlunit), so I could fire the submit of form.

Authentication:

After sending the request I created a CookieManager to obtain the cookies together with the response returned by the server. With that, that problem of scanning all the HTML code of the page and "(...) search for a word that only a logged-in user could see (...)" was resolved. How authentication is done on behalf of cookie, it will always be valid regardless of whether the user is using the forum in Portuguese or English.

Follow the code of the class :)

import com.gargoylesoftware.htmlunit.*;
import com.gargoylesoftware.htmlunit.html.*;
import com.gargoylesoftware.htmlunit.util.Cookie;
import java.io.IOException;

public class VBulletinAuth {
    
    // Elementos no HTML
    private final String
    LOGIN_FORM_ID = "navbar_loginform",   // formulário de login
    LOGIN_USER_NAME = "vb_login_username",// input de username
    LOGIN_PASS_NAME = "vb_login_password",// input de senha
    LOGIN_REMEMBER_NAME = "cookieuser";   // checkbox para manter os cookies
    
    
    // Homepage em que exista um formulário de login
    private final String
    HOMEPAGE = "http://www.forum.com.br/forum";
    
    // cookie para verificar se o usuário logou
    private final String
    SESSION_HASH = "bb_sessionhash";
    
    private final WebClient webClient;
    private CookieManager cookies;

    public VBulletinAuth() {
        webClient = new WebClient(BrowserVersion.CHROME);
        webClient.getOptions().setCssEnabled(false);
        webClient.getOptions().setJavaScriptEnabled(false);
    }
    
    private boolean hasAccount(String user, String pass){
        
        try {
            // Requisição GET para obter a página de login
            HtmlPage homePage = webClient.getPage(HOMEPAGE);
            
            // Procurando pelo formulário de login
            HtmlForm loginForm = null;
            for(HtmlForm form : homePage.getForms())
                if(form.getId().equals(LOGIN_FORM_ID))
                    loginForm = form;
            
            // Obtendo os inputs do formulário  e inserindo os dados de login
            HtmlTextInput usernameInput = loginForm.getInputByName(LOGIN_USER_NAME);
            HtmlPasswordInput passwordInput = loginForm.getInputByName(LOGIN_PASS_NAME);
            HtmlCheckBoxInput rememberMeInput = loginForm.getInputByName(LOGIN_REMEMBER_NAME);
            
            usernameInput.setValueAttribute(user);
            passwordInput.setValueAttribute(pass);
            rememberMeInput.setChecked(true);
            
            // Criando o botão 'fake' de submit e inserindo ele dentro do formulário de login
            HtmlElement fakeSubmitButton = (HtmlElement) homePage.createElement("button");
            fakeSubmitButton.setAttribute("type", "submit");
            loginForm.appendChild(fakeSubmitButton);
            
            // criando uma instância de cookie manager para obter os cookies
            cookies = new CookieManager();
            cookies = webClient.getCookieManager();
            cookies.setCookiesEnabled(true);
            webClient.setCookieManager(cookies);
            
            // Envia o formulário
            fakeSubmitButton.click();
            
            // Verifica se foi criado o cookie de sessao
            for(Cookie cookie : cookies.getCookies())
                if(cookie.getName().equals(SESSION_HASH))
                    return true;

        } catch(IOException | FailingHttpStatusCodeException e){
            // tratamento de exceções
        }
        return false;
    }
    
    // TESTE:
    public static void main(String[] args) {
        VBulletinAuth auth = new VBulletinAuth();
        
        if(auth.hasAccount("renan", "12345")){
            // é membro do fórum
        }
        
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.