Autenticação básica no aplicativo REST

Meio Ambiente:

  • JAVA
  • glassfish
  • Serviços REST em diferentes máquinas
  • Cliente HTML5 com AJAX e JQuery
  • Jersey

Isto é o que eu implementei até agora:

Cliente HTML5 ###

$('#btnSignIn').click(function () { var username = $("#username").val(); var password = $("#password").val(); function make_base_auth(user, password) { var tok = user + ':' + password; var final = "Basic " + $.base64.encode(tok); console.log("FINAL---->" + final); alert("FINAL---->" + final); return final; } $.ajax({ type: "GET", contentType: "application/json", url: "http://localhost:8080/SesameService/webresources/users/secured/login", crossDomain: true, dataType: "text", async: false, data: {}, beforeSend: function (xhr) { xhr.setRequestHeader('authorization', make_base_auth(username, password)); }, success: function () { alert('Thanks for your signin in! '); }, error: function (jqXHR, textStatus, errorThrown) { console.log(textStatus, errorThrown); alert(' Error in signIn-process!! ' + textStatus); } }); }); 

SERVIDOR

Em Segurança, não tenho o Gerenciador de Segurança ativado, ele está desativado!

Eu configurei a autenticação BASIC para o Glassfish e meu web.xml se parece com isso:

  ServletAdaptor /webresources/*    REST Protected resources  /users/*   admin customer user    BASIC jdbcRealm   admin   user    customer  

PEIXE DE VIDRO

insira a descrição da imagem aqui

REGISTRO

 FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/users/secured/login" "GET") FINE: [Web-Security] hasUserDataPermission isGranted: true FINE: [Web-Security] Policy Context ID was: SesameService/SesameService FINE: [Web-Security] hasResource isGranted: true FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/users/secured/login" "GET") 

QUESTÃO:

  1. Se eu criptografar (NÃO codificar) senha no cliente quando o usuário está se inscrevendo e transferi-lo sob o SSL / HTTPS, esta é uma maneira segura e boa de implementar isso?

  2. Se eu usar o serviço REST sem cliente, está sempre aberto, POR QUÊ? Nenhuma autenticação BASIC? Eu entendi algo errado com esses padrões de URL?

     http://localhost:8080/SesameService/webresources/users/secured/login 
  3. Se eu conseguir este trabalho como testar isso, porque agora se eu autenticar uma vez, estou autorizado sempre? É possível “sair” programaticamente dentro do serviço REST ou, em geral, como implementar o logout?

  4. Ao usar a autorização no header com o nome de usuário obrigatório codificado na base64: senha eu tenho que codificar meu nome de usuário e senha para DB também? Eu tentei isso e adicionei codificação (valores permitidos são Hex e Base64) para jdbcRealm para Glassfish e parece que a senha é suficiente, mas o que acontece quando ambos são codificados no cliente?

ATUALIZAÇÃO: Mudei o web.xml e agora a autenticação BASIC está funcionando ao chamar o serviço REST diretamente no navegador: http://localhost:8080/SesameService/users/secured/login

Alterar:

  • Habilitei gerente de segurança em Glassfish
  • Eu mudei o padrão url

    ServletAdaptor / * —-> Eu tirei webresources off. Foi gerado pelo Netbeans

  • Eu mudei o URL para o serviço para isso: http://localhost:8080/SesameService/users/secured/login

Agora eu recebo um HTTP / 1.1 401 não autorizado ao tentar autenticar do cliente HTML5.

Solicitar headers: `

 Origin: http://localhost:8383 Host:`localhost:8080` Connection:keep-alive Access-Control-Request-Method:GET Access-Control-Request-Headers:authorization,content-type` 

Resposta:

 x-powered-by:Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.2.2 Java/Oracle Corporation/1.7) WWW-Authenticate:Basic realm="jdbcRealm" Server:GlassFish Server Open Source Edition 3.1.2.2 Pragma:No-cache Expires:Thu, 01 Jan 1970 02:00:00 EET Date:Sat, 13 Apr 2013 15:25:06 GMT Content-Type:text/html Content-Length:1073 Cache-Control:no-cache 

ATUALIZAÇÃO 2

Quando eu tento autenticar com JavaScript + Authorization-header eu recebi erro 401 e que no log:

 FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/users/secured/login" "OPTIONS") FINE: [Web-Security] hasUserDataPermission isGranted: true---->!!!!!!!!!!!!! FINE: [Web-Security] Policy Context ID was: SesameService/SesameService FINE: [Web-Security] Codesource with Web URL: file:/SesameService/SesameService FINE: [Web-Security] Checking Web Permission with Principals : null------->!!!!!!! FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS") FINEST: JACC Policy Provider: PolicyWrapper.implies, context (SesameService/SesameService)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")) FINE: [Web-Security] hasResource isGranted: false------->!!!!!!!!! FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS") FINEST: JACC Policy Provider: PolicyWrapper.getPermissions(cs), context (null) codesource ((null )) permissions: java.security.Permissions@5d4de3b0 ( 

**** ATUALIZAÇÃO 3 **** Eu não posso ser a primeira e única pessoa que está tentando autenticar usando BASIC no caso de domínio cruzado. Eu mudei meus filtros de origem cruzada assim: response.getHttpHeaders (). PutSingle (“Access-Control-Allow-Headers”, “Authorization”);

Não erro 401 mais, mas ainda erro em JavaScript. No log do Glassfish:

 FINEST: JACC Policy Provider: getPolicy (SesameService/SesameService) is NOT in service----->!!!!!!!! FINE: JACC Policy Provider: file arrival check type: granted arrived: false exists: false lastModified: 0 storedTime: 1365968416000 state: deleted SesameService/SesameService FINE: JACC Policy Provider: file arrival check type: excluded arrived: false exists: false lastModified: 0 storedTime: 0 state: deleted SesameService/SesameService FINE: TM: getTransaction: tx=null, tm=null FINE: TM: componentDestroyedorg.apache.catalina.servlets.DefaultServlet@227fe9a8 FINE: TM: resourceTable before: 0 FINE: TM: resourceTable after: 0 

BTW, porque eu nunca consegui este trabalho, isso funciona da mesma forma que chamar o serviço REST direto em seu próprio domínio. Assim, a janela Solicitações do primeiro cliente, solicitações do servidor e nome de usuário-senha é aberta, então a solicitação do cliente e o servidor autenticam e respondem à página? Eu estou tentando obtê-lo: solicitação com header de autorização, resposta do servidor com resultado do serviço de descanso e é isso. Alguma idéia de como proteger os serviços REST? Mais fácil que isso? Isto é impossível.

ATUALIZAÇÃO 4

Eu apenas tentei mover o meu cliente HTML5 para dentro do projeto web java, apenas páginas html puras e sob o mesmo domínio e a autenticação BASIC está funcionando 100%. Então, a razão é por causa do ambiente de domínio cruzado.

Se eu criptografar (NÃO codificar) senha no cliente quando o usuário está se inscrevendo e transferi-lo sob o SSL / HTTPS, esta é uma maneira segura e boa de implementar isso?

Muito provavelmente você deve simplesmente passar a senha em texto simples via SSL / HTTPS.

Toda a comunicação em SSL / HTTPS é criptografada, portanto, provavelmente não é uma boa ideia criptografar a senha, a menos que você precise garantir que o servidor da Web (tecnicamente, o terminador HTTPS) não possa ver a senha.

Se eu usar o serviço REST sem cliente, está sempre aberto, POR QUÊ? Nenhuma autenticação BASIC? Eu entendi algo errado com esses padrões de URL?

Não tenho certeza se entendi a pergunta. No entanto, o BASIC auth não é um bom padrão para autenticação no REST porque está passando a senha em texto simples.

Se eu conseguir este trabalho como testar isso, porque agora se eu autenticar uma vez, estou autorizado sempre? É possível “sair” programaticamente dentro do serviço REST ou, em geral, como implementar o logout?

Em Basic Auth, o nome de usuário e a senha são passados ​​pelo cliente em todas as solicitações HTTP . Se as credenciais não forem passadas pelo cliente, o servidor rejeitará a solicitação. Como tal, não há conceito de session.

No entanto, no que diz respeito ao servidor Java EE, o login cria uma session do usuário e as solicitações futuras do mesmo usuário usarão a mesma session. Se você configurá-lo, esta session expirará.

Se o logout for importante (isto é, controlar as sessões do usuário), você deverá criar um servlet (/ logout) para isso, o que invalida a session HTTP.

O modelo de segurança padrão do Java funciona da seguinte maneira: Quando o usuário efetua login em uma região de segurança, o servidor Java EE armazena um cookie seguro em seu navegador. O navegador envia esse cookie de volta ao servidor Java EE em cada solicitação para o mesmo domínio. O servidor Java EE verifica esse cookie em cada solicitação e o utiliza para identificar o usuário, conectando a solicitação à session do usuário.

Então você provavelmente quer ter o serviço REST no mesmo domínio de segurança que o aplicativo da Web, para que o navegador e o servidor funcionem perfeitamente.

Ao usar a autorização no header com o nome de usuário obrigatório codificado na base64: senha eu tenho que codificar meu nome de usuário e senha para DB também? Eu tentei isso e adicionei codificação (valores permitidos são Hex e Base64) para jdbcRealm para Glassfish e parece que a senha é suficiente, mas o que acontece quando ambos são codificados no cliente?

Não, não codifique o nome de usuário ou a senha – tudo isso é tratado no navegador e no Glassfish. Se você codificar no cliente, o cliente codificará a codificação e o servidor rejeitará a senha.


Você poderia me dizer se é possível usar j_security_check de html5-page com javaScript ou estou com problemas novamente 🙂 Eu fiz alguns pares de Primefaces + jsf-application onde eu usei o FORM-auth e não houve nenhum problema, mas isso foi totalmente um desastre para mim.

Você deve conseguir que isso funcione confortavelmente com j_security_check, supondo que os serviços RESTful permaneçam no mesmo domínio e região de segurança (então, fazer logon no aplicativo da Web permitirá que o navegador envie o cookie correto para os URIs REST).

Observe, no entanto, que outros aplicativos terão dificuldade em acessar os serviços REST. Basicamente, eles terão que fazer o login através do j_security_check e então manter os cookies enviados pela Glassfish. Se você precisar de outros aplicativos para acessar esses serviços programaticamente, precisará de outra solução:

  1. Você pode configurar o domínio de segurança para permitir que diferentes autenticadores sejam ‘suficientes’; configure o HTTP BASIC Auth também e certifique-se de que nenhum esteja marcado como ‘necessário’
  2. Implante os serviços RESTful duas vezes, sendo o outro um URI diferente. Se você quiser usar HTTP BASIC Auth, isso pode ser um ponto final SSL / HTTPS para garantir que as senhas sejam tratadas com segurança

Eu estou trabalhando na estrutura Spring MVC com segurança de primavera e uso de autenticação básica:

Basicamente, na autenticação básica HTTP, o nome de usuário e a senha são convertidos em uma chave ou em um token de access com a ajuda da class Base64 (do pacote util).

E essa chave é definida no header do URL HTTP e, em seguida, acesse o servidor.

Ele funciona bem e no servidor: decodifique a chave de senha do nome de usuário pelo mesmo Base64 e, em seguida, combine com o nome de usuário e a senha do database. Se a autenticação for feita, processe-a posteriormente.

Isso fornece a segurança dos API Urls. Todo corpo não acessa facilmente.

Código: Criar código de token de access (chave) é:

NOTA: passamos string em Base64 (do pacote util) “YourUsername: YourPassword” para codificação.
Sim, nome de usuário e senha são “:” separados.

  String encodeddata = new String(Base64.encodeBase64("username:password".getBytes())); System.out.println("encodedBytes " + encodeddata); 

Código para definir a chave no header:

// PEDIDO DE URL COM CHAVE

  HttpClient client = HttpClientBuilder.create().build(); HttpGet get = new HttpGet("http://google.com/Abc/api/vou/redeemed"); get.setHeader("Authorization", "Basic "+encodeddata); //key getting above 

Nota: Você pode usar isso com o método Get e Post. Aqui estou usando apenas com método get. //RESPOSTA

  HttpResponse jresponse = client.execute(get); System.out.println("Response Code : "+ jresponse.getStatusLine().getStatusCode()); BufferedReader rd = new BufferedReader(new InputStreamReader(jresponse.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } System.out.println("------Response is ::: "+ result); 

// DECODE Key

  String usernameAndPassword = null; try { usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword)); } catch (Exception e) { System.out.println("SERVER_ERROR"); } System.out.println(usernameAndPassword); final StringTokenizer tokenizer = new StringTokenizer(encodedUserPassword, ":"); final String username = tokenizer.nextToken(); final String password = tokenizer.nextToken(); System.out.println(username); System.out.println(password); 
Intereting Posts