COMPARTE ESTE ARTÍCULO

En este ejercicio avanzado, se te desafía a implementar un sistema cliente-servidor en Java que no solo gestione usuarios y sesiones, sino que también implemente control de acceso basado en roles. Este ejercicio te ayudará a profundizar en conceptos clave como la autenticación, autorización, y la implementación de roles de usuario para controlar el acceso a diferentes recursos.


Ejercicio: Implementación de un Sistema Cliente-Servidor con Gestión de Usuarios, Roles y Control de Acceso

Objetivo:

Desarrollar un servidor HTTP en Java que permita:

  • Registro de usuarios: El servidor debe permitir que los usuarios se registren proporcionando un nombre de usuario, contraseña y un rol (por ejemplo, “admin” o “user”).
  • Inicio de sesión: Los usuarios registrados deben poder iniciar sesión proporcionando sus credenciales.
  • Gestión de sesiones: El servidor debe generar un token de sesión único para cada inicio de sesión exitoso.
  • Control de acceso basado en roles: Dependiendo del rol del usuario, este podrá acceder a diferentes recursos protegidos.
  • Roles de usuario: Los roles deben ser “admin” y “user”, donde “admin” tiene acceso completo y “user” acceso limitado.

Requisitos:

  1. Puerto de Escucha: El servidor debe escuchar en el puerto 8086.
  2. Registro de Usuarios: El cliente debe poder registrar un usuario enviando un nombre de usuario, contraseña, y rol a la ruta /register mediante una solicitud POST.
  3. Inicio de Sesión: El cliente debe poder iniciar sesión enviando un nombre de usuario y contraseña a la ruta /login mediante una solicitud POST.
  4. Gestión de Sesiones: El servidor debe generar un token de sesión único para cada inicio de sesión exitoso.
  5. Control de Acceso: Los recursos protegidos deben ser accesibles según el rol del usuario:
  • /admin: Solo accesible para usuarios con rol “admin”.
  • /user: Accesible para usuarios con rol “user” y “admin”.
  1. Validación del token: El servidor debe validar el token de sesión para conceder o denegar el acceso a los recursos protegidos.

Parte 1: Implementación del Servidor HTTP en Java

El servidor gestionará el registro de usuarios, el inicio de sesión, la validación de tokens, y el control de acceso basado en roles.

Código del Servidor:

package cristinaleonacademiaexamen;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

public class ServidorHTTP {

    private static Map<String, Usuario> usuarios = new HashMap<>();
    private static Map<String, String> sesiones = new HashMap<>();

    public static void main(String[] args) throws IOException {
        HttpServer server = HttpServer.create(new InetSocketAddress(8086), 0);
        server.createContext("/register", new RegistroHandler());
        server.createContext("/login", new LoginHandler());
        server.createContext("/admin", new AdminHandler());
        server.createContext("/user", new UserHandler());
        server.setExecutor(Executors.newCachedThreadPool()); // Manejo concurrente de solicitudes
        server.start();
        System.out.println("Servidor HTTP iniciado en el puerto 8086");
    }

    static class RegistroHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if ("POST".equals(exchange.getRequestMethod())) {
                String[] credenciales = new String(exchange.getRequestBody().readAllBytes()).split("&");
                String nombreUsuario = credenciales[0].split("=")[1];
                String password = credenciales[1].split("=")[1];
                String rol = credenciales[2].split("=")[1];

                if (usuarios.containsKey(nombreUsuario)) {
                    String respuesta = "Usuario ya registrado.";
                    exchange.sendResponseHeaders(409, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                } else {
                    usuarios.put(nombreUsuario, new Usuario(nombreUsuario, password, rol));
                    String respuesta = "Usuario registrado con éxito.";
                    exchange.sendResponseHeaders(200, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                }
            } else {
                exchange.sendResponseHeaders(405, -1); // Método no permitido
            }
        }
    }

    static class LoginHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            if ("POST".equals(exchange.getRequestMethod())) {
                String[] credenciales = new String(exchange.getRequestBody().readAllBytes()).split("&");
                String nombreUsuario = credenciales[0].split("=")[1];
                String password = credenciales[1].split("=")[1];

                if (usuarios.containsKey(nombreUsuario) && usuarios.get(nombreUsuario).getPassword().equals(password)) {
                    String token = UUID.randomUUID().toString();
                    sesiones.put(token, nombreUsuario);

                    String respuesta = "Inicio de sesión exitoso. Token de sesión: " + token;
                    exchange.sendResponseHeaders(200, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                } else {
                    String respuesta = "Credenciales incorrectas.";
                    exchange.sendResponseHeaders(401, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                }
            } else {
                exchange.sendResponseHeaders(405, -1); // Método no permitido
            }
        }
    }

    static class AdminHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String token = exchange.getRequestHeaders().getFirst("Authorization");

            if (sesiones.containsKey(token)) {
                String nombreUsuario = sesiones.get(token);
                Usuario usuario = usuarios.get(nombreUsuario);

                if ("admin".equals(usuario.getRol())) {
                    String respuesta = "Acceso concedido al recurso admin para el usuario: " + nombreUsuario;
                    exchange.sendResponseHeaders(200, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                } else {
                    String respuesta = "Acceso denegado. Este recurso es solo para administradores.";
                    exchange.sendResponseHeaders(403, respuesta.getBytes().length);
                    OutputStream os = exchange.getResponseBody();
                    os.write(respuesta.getBytes());
                    os.close();
                }
            } else {
                String respuesta = "No autorizado. Token de sesión inválido.";
                exchange.sendResponseHeaders(403, respuesta.getBytes().length);
                OutputStream os = exchange.getResponseBody();
                os.write(respuesta.getBytes());
                os.close();
            }
        }
    }

    static class UserHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String token = exchange.getRequestHeaders().getFirst("Authorization");

            if (sesiones.containsKey(token)) {
                String nombreUsuario = sesiones.get(token);
                Usuario usuario = usuarios.get(nombreUsuario);

                String respuesta = "Acceso concedido al recurso user para el usuario: " + nombreUsuario + " con rol: " + usuario.getRol();
                exchange.sendResponseHeaders(200, respuesta.getBytes().length);
                OutputStream os = exchange.getResponseBody();
                os.write(respuesta.getBytes());
                os.close();
            } else {
                String respuesta = "No autorizado. Token de sesión inválido.";
                exchange.sendResponseHeaders(403, respuesta.getBytes().length);
                OutputStream os = exchange.getResponseBody();
                os.write(respuesta.getBytes());
                os.close();
            }
        }
    }

    static class Usuario {
        private String nombreUsuario;
        private String password;
        private String rol;

        public Usuario(String nombreUsuario, String password, String rol) {
            this.nombreUsuario = nombreUsuario;
            this.password = password;
            this.rol = rol;
        }

        public String getNombreUsuario() {
            return nombreUsuario;
        }

        public String getPassword() {
            return password;
        }

        public String getRol() {
            return rol;
        }
    }
}

Explicación del Código:

  1. Gestión de Usuarios con Roles:
  • Los usuarios se registran mediante la ruta /register, enviando un nombre de usuario, contraseña, y rol (“admin” o “user”).
  • La clase Usuario almacena la información de cada usuario, incluyendo su rol.
  1. Inicio de Sesión y Generación de Tokens:
  • La ruta /login permite a los usuarios iniciar sesión. Si las credenciales son correctas, se genera un token de sesión único.
  1. Control de Acceso Basado en Roles:
  • La ruta /admin es accesible solo para usuarios con rol “admin”. Si un usuario con un rol diferente intenta acceder, se deniega el acceso.
  • La ruta /user es accesible para cualquier usuario autenticado, tanto “user” como “admin”.
  1. Validación del Token de Sesión:
  • El servidor verifica que el token de sesión sea válido antes de conceder acceso a los recursos protegidos.

**Parte 2

: Implementación del Cliente Java**

El cliente interactuará con el servidor para registrar usuarios, iniciar sesión, y acceder a recursos protegidos según el rol del usuario.

Código del Cliente:

package cristinaleonacademiaexamen;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class ClienteHTTP {

    public static void main(String[] args) {
        try {
            // Registro de usuario como admin
            String urlRegistro = "http://localhost:8086/register";
            String credencialesRegistro = "usuarioAdmin=passwordAdmin&rol=admin";
            String respuestaRegistro = enviarSolicitudPost(urlRegistro, credencialesRegistro);
            System.out.println("Respuesta del servidor (Registro): " + respuestaRegistro);

            // Inicio de sesión
            String urlLogin = "http://localhost:8086/login";
            String credencialesLogin = "usuarioAdmin=passwordAdmin";
            String token = autenticarUsuario(urlLogin, credencialesLogin);
            System.out.println("Token de sesión: " + token);

            // Acceso a recurso admin usando el token
            String urlAdmin = "http://localhost:8086/admin";
            String respuestaAdmin = accederRecursoProtegido(urlAdmin, token);
            System.out.println("Respuesta del recurso admin: " + respuestaAdmin);

            // Acceso a recurso user usando el token
            String urlUser = "http://localhost:8086/user";
            String respuestaUser = accederRecursoProtegido(urlUser, token);
            System.out.println("Respuesta del recurso user: " + respuestaUser);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String enviarSolicitudPost(String urlStr, String datos) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection conexion = (HttpURLConnection) url.openConnection();
        conexion.setRequestMethod("POST");
        conexion.setDoOutput(true);

        try (OutputStream os = conexion.getOutputStream()) {
            os.write(datos.getBytes());
            os.flush();
        }

        BufferedReader in = new BufferedReader(new InputStreamReader(conexion.getInputStream()));
        String inputLine;
        StringBuilder contenido = new StringBuilder();

        while ((inputLine = in.readLine()) != null) {
            contenido.append(inputLine);
        }

        in.close();
        return contenido.toString();
    }

    private static String autenticarUsuario(String urlStr, String credenciales) throws Exception {
        String respuesta = enviarSolicitudPost(urlStr, credenciales);
        return extraerTokenDeRespuesta(respuesta);
    }

    private static String extraerTokenDeRespuesta(String respuesta) {
        int inicio = respuesta.indexOf("Token de sesión: ") + 17;
        return respuesta.substring(inicio);
    }

    private static String accederRecursoProtegido(String urlStr, String token) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection conexion = (HttpURLConnection) url.openConnection();
        conexion.setRequestMethod("GET");
        conexion.setRequestProperty("Authorization", token);

        BufferedReader in = new BufferedReader(new InputStreamReader(conexion.getInputStream()));
        String inputLine;
        StringBuilder contenido = new StringBuilder();

        while ((inputLine = in.readLine()) != null) {
            contenido.append(inputLine);
        }

        in.close();
        return contenido.toString();
    }
}

Explicación del Código:

  1. Registro de Usuarios con Rol:
  • El cliente envía una solicitud POST al servidor con las credenciales y el rol del nuevo usuario. El servidor responde si el registro fue exitoso.
  1. Inicio de Sesión:
  • El cliente envía las credenciales a la ruta /login. Si el inicio de sesión es exitoso, el servidor devuelve un token de sesión.
  1. Acceso a Recursos Protegidos según el Rol:
  • El cliente utiliza el token de sesión para acceder a recursos protegidos en las rutas /admin y /user.
  • La ruta /admin solo es accesible para usuarios con el rol “admin”, mientras que la ruta /user es accesible para todos los usuarios autenticados.
  1. Métodos Auxiliares:
  • enviarSolicitudPost: Envía una solicitud POST al servidor con los datos proporcionados.
  • autenticarUsuario: Gestiona el proceso de inicio de sesión y obtiene el token de sesión.
  • accederRecursoProtegido: Envía una solicitud GET al recurso protegido utilizando el token de sesión.

Conclusión

Este ejercicio avanzado de cliente-servidor en Java te permite implementar un sistema completo que gestiona usuarios, roles, y acceso a recursos protegidos. La implementación de roles agrega un nivel adicional de complejidad y seguridad, asegurando que solo los usuarios con los permisos adecuados puedan acceder a ciertos recursos. Este ejercicio es ideal para prepararte para situaciones más complejas en un examen o en la vida profesional, al proporcionar una comprensión profunda de cómo implementar seguridad y control de acceso en sistemas distribuidos en Java. ¡Espero que lo encuentres desafiante y útil para tu aprendizaje!

… … …

¡Coméntanos que te ha parecido este artículo al final de la página!

TÚ OPINIÓN IMPORTA


NUESTRAS ÚLTIMAS PUBLICACIONES

Contenido restringido

Acceso de usuarios existentes
   
Registro de un nuevo usuario
*Campo necesario

Categories:

Tags:

Comments are closed

Estado de acceso
ESTADO DE ACCESO
TRADUCTORES
COMPARTENOS
error: CONTENIDO PROTEGIDO