Introdução ao ACL do CakePHP

E ae blz?

Novamente, como sempre, igual todas vezes anteriores, mais um post meu saiu de uma conversa que tive no gtalk/msn com alguém, dessa vez foi uma sugestão do João que escreve aqui no technócil comigo, falar sobre o Access Control Lists do CakePHP.

Então vamo lá,

Eu comecei esse post planejando falar sobre ACL num post só, mas vi que seria impossível por que o post ia ficar imenso e no final dele você já teria esquecido o começo então resolvi separar o post em partes.

–Introdução ao ACL do CakePHP
–ACL na prática, controla os acesso tudo amigo!… (hehe o final é título provisório, to criativo hoje)

O objetivo deste post é só introduzir huhuhu! os programadores aos conceitos do ACL, até por que postar tudo deixaria o post grande pra c@#%&*#, etc, etc… que são na verdade o mais complicado de se entender, depois que os conceitos já estão, digamos, entendidos, a implementação é bem mais rápida…

O Access Control Lists, O mano ACL para os íntimos, é um componente que faz parte do core do framework CakePHP, e tem por finalidade oferecer uma forma poderosa de controle e níveis de acesso a determinadas áreas das aplicações.

Uma coisa muito importante que confunde muito quem está estudando o ACL pela primeira vez é, o ACL não faz autenticação ele só facilita a gerência dos níveis, usuários e áreas de acesso.

Resumindo, o que ele faz é dizer quem pode acessar o que, e só.

O ACL usa dois tipos de definições como convenção para facilitar o controle de acesso, são elas:

ACO = Access Control Object, algo que é acessado.

ARO = Access Request Object, quem ou o que acessa algo.

Fazendo uma analogia ao modelo que é geralmente usado pela grande maioria dos programadores, um exemplo de como seriam identificados os controles e níveis de acesso do blog usando ACL, você teria o seguinte cenário.

AROs – Tipos/Grupos de usuários, usuários
Tipos de Usuários:
–Admin
–Editors
–Guest

Usuários:
–Tobias
–João Vagner
–Editor
–Visitante

ACOs – Áreas protegidas
–Posts
–Páginas
–Links
–Plug-ins
–Ferramentas
–Usuários
–Configurações

O ACL tem uma estrutura do tipo árvore e que pode aceitar heranças de permissões de acesso.

Seguindo o exemplo acima poderia ter uma árvore de permissões da seguinte maneira.

Admins (permissões de acesso: todas as áreas)
--João Vagner (herda todas as permissões do grupo)
--Tobias (herda todas as permissões do grupo)

Editors ( permissões de acesso: ( posts (read,add,edit) )
--editor (herda permissões do grupo, usuários (edit:id = editor.id))

Guest (posts,pages,links(read))
--visitante(herda permissões)

WTF? É o que você que nunca mexeu com ACL deve estar no momento né? Relaxa vou explicar o que eu quis dizer com o texto em negrito acima.

Do ponto de vista do ACL tanto os grupos de usuário, quanto os usuários são coisas do mesmo tipo, são coisas que acessam coisas, e graças a metodologia de árvore essas coisas podem herdar permissões de acesso.

No caso do primeiro grupo, Admins, não há nada de especial ou misterioso, o grupo admin tem acesso a tudo e todos os usuários pertencentes a esse grupo herda suas permissões, moleza se você precisa de um controle de acesso simples assim você nem precisa de ACL.

Vamos ao segundo exemplo, esse sim tem algo de interessante e pra alguns pode ter sido meio confuso.

Editors ( permissões de acesso: ( posts (read,add,edit) )
Traduzindo: O grupo Editors tem acesso ao controle posts e tem permissões para efetuar read, add, edit.

O que são essas permissões de read, add, edit? São permissões que você define de acordo com a sua necessidade, eu usei essas por que são as mais básicas, quase um default para exemplos.

Continuando…
--editor (herda permissões do grupo, usuários (edit:id = editor.id))
Traduzindo: O usuário (ARO) editor herda as permissões do grupo editors e tem a permissão específica de edit a determinada id do controllers usuários, o que significa que ele pode editar as próprias informações de usuário, mas não pode editar os dados de outros usuários.

Guest (posts,pages,links(read))
--visitante(herda permissões)

E para todos os visitantes a permissão de ler posts, pages e links.

Como o objetivo desse post é fazer os conceitos serem entendidos não vou postar códigos eles ficam pro próximo post, bom feriado pra todos, e novamente, como sempre, igual a todas as vezes, dúvidas, sugestões e puxões de orelha os comentários tão ai pra isso.

flw ae :)

Encontro de desenvolvedores CAKE Sao Paulo

Bom dia pessoal,

Estive presente no Encontro de desenvolvedores CAKE em Sao Paulo, e posso dizer que foi um bom encontro, palestras de nivel muito bom, aonde foi abordado desde a criação de um helper ate a criação, plugins, ambiente de testes, brincadeiras e criação com o bake.

Algumas palestras em destaques para TDD – Test-Driven Development e Testes Automatizados com CakePHP, aonde foram abordados assuntos que vem ja a algum tempo sendo levado em conta que e desde a engenharia de software ate a cobertura de testes dos codigos. Abordados tipos de testes: Unitarios, Aceitação, entre outros. Palestras de Rodrigo Moyle e José Pedrini.

Apos isso uma outra palestra de nivel incrivel sobre criação e consumo de webservices com CAKEPHP que foi criado e desenvolvido um webservive utilizando REST. Parabéns ao Carlos Pires da 2KM que veio de Minas para nos prestegiar com sua palestra e sua participação no evento.

Um grade destaque também a palestra do Rafael Santos, que nos mostrou como construir uma plataforma RAD para Flex com CakePHP e Fake, apresentando inovações como o FAKE e integrações bem legais entre Flex e CAKEPHP, aonde se utiliza todos os recursos, desde validations, ate os models e controllers, nao deixando a desejar nem um pouco.

Parabéns aos Organizadores, ao Renan Gonçalves que se esforçou e fez acontecer e valer a pena o evento. Troca de conhecimentose fortalecimento da comunidade CAKEPHP e PHP no Brasil e em São Paulo.

Minha Palestra:

Bloqueio de rota administrativa do CakePHP

Olá Pessoal,

Quem utiliza o Fremwork CakePHP sabe que é uma mão na roda o route admin. Nos poupa um bocado de trabalho criar as funções da administração do site. Isso graças ao “Bake” Porém a rota não pode ficar totalmente acessivel a qualquer um, certo?

O Jonathan Snook escreveu um artigo em relação a isso, porém em alguns testes por aqui nenhum realmente funcionou utilizando .htaccess para proteção dessa rota com password.

Password Protecting Admin Functions in CakePHP.

O Conceito da proteção no artigo do Jonathan Snook é simples, E pode ser gerado com qualquer um que possua acesso ao SSH do site. Não é necessário acesso root para esses tipos de ações no servidor.
Seu servidor não te da acesso ao SSH? Está na hora de mudar para a IW²

O primeiro passo dessa proteção se dá ao inserir seguinte conteúdo no seu .htaccess :

1
2
3
4
AuthUserFile /diretorio/passwd/protecao
AuthName "Administracao CAKE"
AuthType Basic
Require valid-user

Com acesso ao ssh utilize o seguinte comando dentro da pasta “www”.

htpasswd -c /diretorio/passwd/protecao username

.
Isso gera um arquivo com a senha criptografada! Caso queira barar o arquivo gerado para verificar fiquem à vontade!

Bons testes, aqui nunca funcionou!

Meu jeitinho

A maneira no qual eu utilizo é a verificação simples de variavel, ou seja, apenas um usuário dentro do código no qual após o POST, verifica os dados, e grava uma sessão, se os mesmos forem iguais.

Primeiro passo é abrir o seu /app/config/routes.php, e crie uma rota chamada admin, usando o controller de páginas estáticas. Veja:

1
Router::connect('/admin/', array('controller' => 'pages', 'action' => 'display', 'admin'));

Agora crie um arquivo chamado admin.ctp dentro da pasta /app/views/pages/ com um formulário básico para login e senha:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php  
//Define o layout padrão para a página
$this->layout = 'admin'; 
?>
<h1><?php __('Administração');?></h1>
<?php   
// Caso ocorra algum erro, é exibido em sua div correta!
if(isset($error)) {   
    echo "<div class='error'>" . $error . "</div>";   
}   
?>   
<?php 
/*
criamos um formulário com o vetor User, indicando a rota /admin/login, onde teremos nossa verificação de usuário e senha para registro da sessão da administração, e acesso ao restante dos actions _admin_
*/
echo $form->create('User', array('url'=>'/admin/login/'));
?>   
<fieldset>
    <legend>Digite os dados</legend>   
        <?php  echo $form->input('username', array('label'=>'Login')); ?>
        <?php echo $form->input('password', array('label'=>'Senha', 'id'=>'Senha')); ?>   
  <?php echo $form->end('Logar!'); ?>   
   </fieldset>
</form>

O próximo passo é criar uma nova rota no /app/config/routes.php, rota no qual foi definida na URL do nosso formulário, onde será submetida os dados para verificação.

1
Router::connect('/admin/login/', array('controller' => 'users', 'action' => 'admLogin'));

Claro, obviamente eu já possuo um controller chamado users, caso não tenha, pode cria-lo, utilizando o código abaixo:

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
<?php
class UsersController extends AppController {
 
	var $name = 'Users';
	var $helpers = array('Html', 'Form');
 
/*
Claro, que aqui irão outras actions suas ;)
*/
 
	function admLogin() {   
	    //verifica se o post possui alguma informação para registrar o nosso array com informações
	    if($this->data) {   
                $dbuser	=       array('username'=='Administrador', 'password'=>'Sua_senha_aqui');
	           if(($this->data['User']['username'] == $dbuser['username']) && 
                         ($this->data['User']['password'] == $dbuser['password']))  {   
                                 $this->Session->Write('admin', $dbuser);   
                                 // registra a sessão "admin" para futuras verificações
                                 $this->Session->setFlash('Logado com sucesso');   
                                 //Notifica o sucesso ao logar!
                                 $this->redirect('/admin/users/index');   
                                 // redireciona para a action index do controller users.
	        } else {   
	              $this->Session->setFlash('Erro! Dados inválidos');
                          // notifica o erro    
	        }   
	    }   
	}
 
 
}
?>

Note que por enquanto o nosso controller users possui apenas um action. Fica a seu critério a criação do resto do conteúdo ;)

Agora iremos criar a função para verificação da sessão:

1
2
3
4
5
6
7
8
9
<?php
	function checkAdminSession() {   
               if (!$this->Session->check('admin')) {   
               $this->Session->setFlash('Você não tem acesso a essa área');   
               $this->redirect('/admin/login/');   
    }   
}   
 
?>

A minha recomendação é que coloque essa função dentro do arquivo /app/app_controller.php no qual o cake carrega automáticamente. Esse arquivo serve para colocar as funções que vai utilizar em todos os controllers, sem a necessidade de ficar repetindo os mesmos.

Agora vem a parte mais interessante, vamos inserir o beforeFilter(); também dentro do /app/app_controller.php, para verificação do parametro /admin/ na url, e execução da verificação da sessão. Veja:

1
2
3
4
5
6
7
8
<?php
 
function beforeFilter() {   
        if(isset($this->params['admin'])) {   
           $this->checkAdminSession();   
    }   
 }
?>

O que a função faz é: Se existe algum parametro na url “admin”, executa a função checkAdminSession e veja se existe a sessão “admin”. Se não existir a sessão, a checkAdminSession redireciona para login.

Pronto, e assim você tem uma certa segurança em relação a rota /admin/ não estar sendo visualizada por tudo e por todos!