読者です 読者をやめる 読者になる 読者になる

m_shige1979のささやかな抵抗と欲望の日々

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

なんとなく作ったサイト

http://www.it-check-matome.info/


Github(注意すること)

https://github.com/mshige1979

Apache Directory Studioでdcやouなどを作成する

Apache DS LDAP Active Directory

今回やること

dc=hogehoge,dc=comみたいなものを作成する

順番

  1. パーティションを作成
  2. dcを作成
  3. ouを作成

uidを作成

パーティションを作成

「Connectiros」の「Open Configuration」を選択して設定情報を開く

f:id:m_shige1979:20170128180114p:plain

「Advanced Partitions configuration」をクリックします

f:id:m_shige1979:20170128180243p:plain

「Add」ボタンを新しいパーティション情報を追加する

f:id:m_shige1979:20170128180529p:plain

Apache DSを再起動する
sudo /etc/init.d/apacheds-2.0.0_M23-default restart

※先にApache Directory Studioの接続情報は切断しておく

再接続して確認

f:id:m_shige1979:20170128180841p:plain

組織単位(ou)の作成

作成したドメインを選択して、「New Context Entry」を選択

f:id:m_shige1979:20170128181218p:plain

「Create entry from scratch」を選択して次へ

f:id:m_shige1979:20170128181347p:plain

オブジェクトクラスを追加

f:id:m_shige1979:20170128181601p:plain

DN名を設定

f:id:m_shige1979:20170128181805p:plain

「Finish」

f:id:m_shige1979:20170128182152p:plain

作成

f:id:m_shige1979:20170128182312p:plain

ユーザーを作成

dcまたはouを選択して、「New Entry」を選択

f:id:m_shige1979:20170128182653p:plain

「Create entry from scratch」を選択する

f:id:m_shige1979:20170128182804p:plain

オブジェクトクラスを追加

f:id:m_shige1979:20170128182912p:plain

DNを設定

f:id:m_shige1979:20170128183817p:plain

必要な属性情報を設定する

f:id:m_shige1979:20170128183918p:plain

※設定情報

objectClass organizationalPerson
objectClass inetOrgPerson
objectClass person
objectClass top
cn 任意で設定
sn 任意で設定
uid 任意で設定
userPassword
作成完了

f:id:m_shige1979:20170128184030p:plain

uidではなく、cnで認証したい場合

f:id:m_shige1979:20170128184923p:plain

※設定情報

objectClass organizationalPerson
objectClass person
objectClass top
cn 任意で設定
sn 任意で設定
userPassword 任意で設定

所感

知識がないので作成するまでの調査に時間がかかりすぎました(´・ω・`)
実際はActive Directory Serverなどで設定するのでしょうが今回は同じような環境を構築したい気持ちだったのでこれで満足。
cnとかouとかの知識がちょっとずつ入っている感じです。
認証方法にも複数の方法があるようなのでその辺も調べてみる。

LDAP認証を試してみたい

認証 LDAP

LDAP認証

LDAPとは、LDAP認証とは、LDAP認証 with Cisco ASAより抜粋

LDAP(Lightweight Directory Access Protocol)は、Active Directoryのようなディレクトリサービスにアクセスするためのプロトコル

なるほど

試用してみるLDAPサーバ

Downloads for Linux RPM Package — Apache Directory
※上記よりApacheDSと管理ツールのApache DS Studioをダウンロードしてインストールする

環境

ApacheDS

Vangrantの中のCentOS7

Apache Directory Studio

Mac

Apache DSのインストール

Javaのインストール
sudo rpm -ivh jdk-8u121-linux-x64.rp

Javaを使用しているらしいのでインストールが必要

ダウンロード
curl -o apacheds-2.0.0-M23-x86_64.rpm http://ftp.meisei-u.ac.jp/mirror/apache/dist//directory/apacheds/dist/2.0.0-M23/apacheds-2.0.0-M23-x86_64.rpm
インストール
sudo rpm -ivh apacheds-2.0.0-M23-x86_64.rpm
起動
sudo /etc/init.d/apacheds-2.0.0_M23-default start

管理ツール

Apache Directory Studioを起動

f:id:m_shige1979:20170128072509p:plain

新しくコネクションを作成

f:id:m_shige1979:20170128074633p:plain

接続情報を設定

f:id:m_shige1979:20170128074649p:plain

ホスト LDAPサーバのIP
ポート 10389
ユーザーとパスワードを設定

f:id:m_shige1979:20170128074832p:plain
※テスト情報

認証 simple
ユーザーID uid=admin,ou=system
パスワード secret
完了

f:id:m_shige1979:20170128075039p:plain

画面に表示

f:id:m_shige1979:20170128075151p:plain

Javaで接続

Sample01.java
import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public class Sample01 {

	public static void main(String[] args) {
		System.out.println(auth("uid=admin;ou=system", "secret"));
		System.out.println(auth("uid=admin;ou=system", "ddddddddd"));
	}
	
	public static boolean auth(String uid, String password) {
		boolean res = false;
		
		//LDAP接続情報
		Hashtable env = new Hashtable();
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		env.put(Context.PROVIDER_URL, "ldap://192.168.33.10:10389/"); //LDAPサーバ
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		env.put(Context.SECURITY_PRINCIPAL, uid); //ID, 組織
		env.put(Context.SECURITY_CREDENTIALS, password); //パスワード
		 
		try {
		    DirContext ctx = new InitialDirContext(env);
		    ctx.close();
		    System.out.println("auth ok");
		    res = true;
		} catch (AuthenticationException ae) {
		   //認証エラー
		    System.out.println("auth ng");
		} catch (Exception e) {
		   //その他のエラー
		}
		
		return res;
	}

}

auth ok
true
auth ng
false

所感

基本、Active Directory Serviceとかよくわかっていないけどこれを機会に理解を深めていきたいと思う。
まあ、使わなかったらそれまでなんですけど…
SSLを使う方法も調べて見よう。

Spring Bootで簡易テストを行う

Java Spring Boot テスト

ぶっちゃけ

簡単じゃない
結構めんどくさい

やりたいこと

RestControllerをテストする
Serviceなどを使用している場合はモック化する

実装

Sample01Controller
package com.example.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.dto.sample01.Sample01ReqDto;
import com.example.dto.sample01.Sample01ResDto;
import com.example.service.Check1Service;

@RestController
public class Sample01Controller {
	
	private static final Logger logger = LoggerFactory.getLogger(Sample01Controller.class);
	
	@Autowired
	private Check1Service check1Service;
	
	@ResponseBody
	@RequestMapping(value = "/sample01/test1", method = {RequestMethod.POST}, consumes = MediaType.APPLICATION_JSON_VALUE)
	public Sample01ResDto test1(@RequestBody Sample01ReqDto req) {
		Sample01ResDto res = new Sample01ResDto();
		
		if (check(req)) {
			res.message = "ok";
			res.status = 100L;
		} else {
			res.message = "ng";
			res.status = 900L;
		}
		
		check1Service.sample1();
		
		return res;
	}
	
	private boolean check(Sample01ReqDto req) {
		return check1Service.check(req.name);
	}
	
}

Check1Service
package com.example.service;

import org.springframework.stereotype.Service;

import com.example.dto.sample01.Sample01ReqDto;

@Service
public class Check1Service {
	
	public boolean check(String name) {
		boolean res = false;
		
		if (name != null) {
			res = true;
		}
		
		return res;
	}
	
	public void sample1() {
		String str = "1111";
		str += "222";
	}
	
}
Sample01ReqDto.java
package com.example.dto.sample01;

import java.io.Serializable;

public class Sample01ReqDto implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public String name;
	public Long age;

}
Sample01ResDto.java
package com.example.dto.sample01;

import java.io.Serializable;

public class Sample01ResDto implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public String result;
	public String message;
	public Long status;
}

実行

curl -X POST -H "Content-type: application/json" -d '{"name": null, "age": 100 }' http://localhost:8080/sample01/test1
{"result":null,"message":"ng","status":900}

テストコード

Sample01ControllerTest.java
package com.example.controller;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNotNull;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;

import org.hamcrest.Matchers;
import org.hamcrest.core.IsNull;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.example.dto.sample01.Sample01ReqDto;
import com.example.service.Check1Service;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class Sample01ControllerTest {
	
	@Rule
	public MockitoRule mockitoJUnitRule = MockitoJUnit.rule();
	
    private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(),
            Charset.forName("utf8"));
    
    private MockMvc mockMvc;
    private HttpMessageConverter mappingJackson2HttpMessageConverter;
    
    @InjectMocks
    private Sample01Controller target;
    
    @Autowired
    private WebApplicationContext webApplicationContext;
    
    @Autowired
    void setConverters(HttpMessageConverter<?>[] converters) {

        this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream()
            .filter(hmc -> hmc instanceof MappingJackson2HttpMessageConverter)
            .findAny()
            .orElse(null);

        assertNotNull("the JSON message converter must not be null",
                this.mappingJackson2HttpMessageConverter);
    }
    
    @Mock
    private Check1Service check1Service;
    
    @Before
    public void setup() throws Exception {
        this.mockMvc = MockMvcBuilders.standaloneSetup(target).build();
    }
    
    /**
     * /sample01/test1
     * @throws Exception
     */
    @Test
    public void sample01Test1Post1() throws Exception {
        
        // リクエストパラメータ
        Sample01ReqDto req = new Sample01ReqDto();
        req.name = "aaaa";
        req.age = 100L;
        String jsonSample01ReqDto = json(req);
        
        // 外部クラスをmock化
        check1Service_check();
        
        // 実行
        this.mockMvc.perform(post("/sample01/test1")
                .contentType(contentType)
                .content(jsonSample01ReqDto))
                // ステータスコード
                .andExpect(status().isOk())
                // json項目のNULLチェック
                .andExpect(jsonPath("result").value(IsNull.nullValue()))
                // json項目の文字列チェック
                .andExpect(jsonPath("message", is("ok")))
                // json項目のLong型チェック
                .andExpect(jsonPath("status").value(100L))
                ;
        
    }
    
    /**
     * /sample01/test1
     * @throws Exception
     */
    @Test
    public void sample01Test1Post2() throws Exception {
        
        // リクエストパラメータ
        Sample01ReqDto req = new Sample01ReqDto();
        req.name = null;
        req.age = 200L;
        String jsonSample01ReqDto = json(req);
        
        // 外部クラスをmock化
        check1Service_check();
        
        // 実行
        this.mockMvc.perform(post("/sample01/test1")
                .contentType(contentType)
                .content(jsonSample01ReqDto))
                // ステータスコード
                .andExpect(status().isOk())
                // json項目のNULLチェック
                .andExpect(jsonPath("result").value(IsNull.nullValue()))
                // json項目の文字列チェック
                .andExpect(jsonPath("message", is("ng")))
                // json項目のLong型チェック
                .andExpect(jsonPath("status").value(900L))
                ;
    }
    
    /**
     * /sample01/test1
     * @throws Exception
     */
    @Test
    public void sample01Test1Get() throws Exception {
        
        // 実行
        this.mockMvc.perform(get("/sample01/test1")
                .contentType(contentType))
                // ステータスコード
                .andExpect(status().isMethodNotAllowed())
                ;
    }
    
    // mock化
    private void check1Service_check() {
    	// 値を設定した場合はtrue
    	when(check1Service.check(Mockito.anyString())).thenReturn(true);
    	// 値を未設定の場合はfalse
        when(check1Service.check(null)).thenReturn(false);
        
        // 戻り値がないスタブ
        doNothing().when(check1Service).sample1();
    }
        
    protected String json(Object o) throws IOException {
        MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
        this.mappingJackson2HttpMessageConverter.write(
                o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
        return mockHttpOutputMessage.getBodyAsString();
    }
    
}

やっていること

@Before
    @Before
    public void setup() throws Exception {
        this.mockMvc = MockMvcBuilders.standaloneSetup(target).build();
    }

全てのテストのメソッド前に実行されるモックオブジェクト?を作るはず
@InjectMocksしたコントローラークラスを設定することでスタブを利用できるような感じかと…

@Mock
    @Mock
    private Check1Service check1Service;

モック化したい処理をこういうふうに定義しておく
whenで実行してモックの実行結果を取得する場合に必要

@Test
    @Test
    public void sample01Test1Post1() throws Exception {
        
        // リクエストパラメータ
        Sample01ReqDto req = new Sample01ReqDto();
        req.name = "aaaa";
        req.age = 100L;
        String jsonSample01ReqDto = json(req);
        
        // 外部クラスをmock化
        check1Service_check();
        
        // 実行
        this.mockMvc.perform(post("/sample01/test1")
                .contentType(contentType)
                .content(jsonSample01ReqDto))
                // ステータスコード
                .andExpect(status().isOk())
                // json項目のNULLチェック
                .andExpect(jsonPath("result").value(IsNull.nullValue()))
                // json項目の文字列チェック
                .andExpect(jsonPath("message", is("ok")))
                // json項目のLong型チェック
                .andExpect(jsonPath("status").value(100L))
                ;
        
    }

各テスト処理を実施する。@Testアノテーションを付与したメソッドを全て実行する。

when
    // mock化
    private void check1Service_check() {
    	// 値を設定した場合はtrue
    	when(check1Service.check(Mockito.anyString())).thenReturn(true);
    	// 値を未設定の場合はfalse
        when(check1Service.check(null)).thenReturn(false);
        
        // 戻り値がないスタブ
        doNothing().when(check1Service).sample1();
    }

※スタブに引数と戻り値を設定する。引数を固定値を指定した場合はその値の結果しか返さない

f:id:m_shige1979:20170115180018p:plain

所感

テスト自体はしなくてはいけないとおもいつつも動作確認することで対応すればよいよね…
みたいな感じになるからついやらなくなってしまいます。
今回はきちんとやってみることにする画面関連のテストは無理のような感じがするけどRest APIのようにデータの流れを理解することで対応する。

まあ、あとは実装時にモック化しやすいように考慮しておく

Spring Bootでログを出力する

Java ログ Spring Boot

デバッグ中の場合とかにデータの動きを少しずつ確認したい場合など

ログを出力して確認します。
System.out.printlnではよくわからない場合など…

サンプル

Sample01Controller
package com.example.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.dto.sample01.Sample01ReqDto;
import com.example.dto.sample01.Sample01ResDto;

@RestController
public class Sample01Controller {
	
	private static final Logger logger = LoggerFactory.getLogger(Sample01Controller.class);
	
	@ResponseBody
	@RequestMapping(value = "/sample01/test1", method = {RequestMethod.POST}, consumes = MediaType.APPLICATION_JSON_VALUE)
	public Sample01ResDto test1(@RequestBody Sample01ReqDto req) {
		Sample01ResDto res = new Sample01ResDto();
		
		logger.info("log sample1");
		logger.debug("log sample2");
		logger.warn("log sample3");
		logger.error("log sample4");
		
		return res;
	}
	
}

2017-01-15 16:14:58.197  INFO 35008 --- [nio-8080-exec-1] c.example.controller.Sample01Controller  : log sample1
2017-01-15 16:14:58.197  WARN 35008 --- [nio-8080-exec-1] c.example.controller.Sample01Controller  : log sample3
2017-01-15 16:14:58.197 ERROR 35008 --- [nio-8080-exec-1] c.example.controller.Sample01Controller  : log sample4

※debug以外は確認できる。おそらくなんか表示条件が違うのでしょう…

今回はとりあえずここまで…

JavaのFreeMakerでテンプレート処理を行う2

Java テンプレート freemarker

インクルード処理を使う

1つのテンプレートの中に他のテンプレートファイルを読み込みます。

pom.xml

  <dependencies>
    
    <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>

  </dependencies>
ml|

テンプレートファイル

sample2.ftl
<#-- header -->
<#include "parts/header.ftl">

<#-- contents -->
${contents}

<#-- footer -->
<#include "parts/footer.ftl">
parts/header.ftl
----------------------
header情報です。
----------------------
${header}
parts/footer.ftl
----------------------
footer情報です。
----------------------
${footer}

実装

Sample02.java
package com.example;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class Sample02 {

	public static void main(String[] args) throws IOException, TemplateException {
		
		// 初期化
		Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
		
		// ディレクトリを指定
		cfg.setDirectoryForTemplateLoading(new File("src/main/resources/template"));
		
		// テンプレートファイルを指定
		Template temp = cfg.getTemplate("sample2.ftl");
		
		// データモデル
		Map<String, String> root = new HashMap<String, String>();
		root.put("header", "ヘッダーのデータを表示中");
		root.put("contents", "テストデータです。");
		root.put("footer", "フッターのデータを表示中");
		
		// テンプレート処理
		Writer out = new StringWriter();
		temp.process(root, out);
		out.flush();
		
		// 結果出力
		String displayStr = out.toString();
		System.out.print(displayStr);
	}
}

※ヘッダー、フッターのものも一緒に定義する必要がある。

header情報です。
----------------------
ヘッダーのデータを表示中

テストデータです。

----------------------
footer情報です。
----------------------
フッターのデータを表示中

うん、想定どおりで安心しました。

今回はここまで…

JavaのFreeMakerでテンプレート処理を行う

Java freemarker テンプレート

テンプレート処理

HTMLなどでヘッダー部分やフッター部分など
ある程度共通の部分は別ファイルで管理して読み込みたいことがありますのでテンプレートとして使用します。

FreeMaker

Javaのテンプレートエンジンとのこと
仕事でJava使うのはほとんどなかったので調べてみる。

設定

pom.xml
  <dependencies>
    
    <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>

  </dependencies>

テンプレートファイル

sampl1.ftl
<#-- name -->
name: ${name}
<#-- age -->
age: ${age}

<#-- biko -->
<#if biko?has_content>
biko: ${biko}
</#if>

うん、まあ意味は分かる。変数を割り当てるような感じ

実装

Sample01.java
package com.example;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class Sample01 {

	public static void main(String[] args) throws IOException, TemplateException {
		
		// 初期化
		Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
		
		// ディレクトリを指定
		cfg.setDirectoryForTemplateLoading(new File("src/main/resources/template"));
		
		// テンプレートファイルを指定
		Template temp = cfg.getTemplate("sample1.ftl");
		
		// データモデル
		Map<String, String> root = new HashMap<String, String>();
		root.put("name", "hoge");
		root.put("age", "100");
		root.put("vvvv", "ddddd");	// 未定義のものは設定してもエラーにならない
		
		// テンプレート処理
		Writer out = new StringWriter();
		temp.process(root, out);
		out.flush();
		
		// 結果出力
		String displayStr = out.toString();
		System.out.print(displayStr);
	}
}

※標準出力に返すサンプルが多かったけどあんまり好きじゃないので文字列に設定してみました。

name: hoge
age: 100

できました(^^)

所感

とりあえず、こんな感じ
これだけじゃああまり有用ではないので他のファイルを読み込めることを調べてみる

AWSのSESでメールを送信2

Java SES AWS メール

SESでメールを送信するもう1つの方法

を試してみる

サンプル

Sample02.java
import java.util.Properties;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.simpleemail.AWSJavaMailTransport;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient;
import com.amazonaws.services.simpleemail.model.ListVerifiedEmailAddressesResult;
import com.amazonaws.services.simpleemail.model.VerifyEmailAddressRequest;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class Sample02 {
	
    private static final String ACCESS_KEY = "アクセスキー";
    private static final String SECRET_ACCESS_KEY = "シークレットアクセスキー";
	
    public static void main(String[] args) throws AddressException, MessagingException {
		
        String TO = "送信先のメール";
        String FROM = "送信元のメール";
        String SUBJECT = "テストメール";
        String BODY = "テストメールです。";
		
        // 認証
        AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_ACCESS_KEY);
        AmazonSimpleEmailService ses = new AmazonSimpleEmailServiceClient(credentials);
	ses.setRegion(Region.getRegion(Regions.US_WEST_2));

        // 送信元認証
        verifyEmailAddress(ses, FROM);
        verifyEmailAddress(ses, TO);
	    
        // 設定
        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "aws");
        props.setProperty("mail.aws.user", credentials.getAWSAccessKeyId());
        props.setProperty("mail.aws.password", credentials.getAWSSecretKey());
        props.setProperty("mail.aws.host", "email.us-west-2.amazonaws.com");
        Session session = Session.getDefaultInstance(props);
	 
        // メッセージ作成
        Message msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress(FROM));
        msg.addRecipient(Message.RecipientType.TO, new InternetAddress(TO));
        msg.setSubject(SUBJECT);
        msg.setText(BODY);
        msg.saveChanges();
	 
        // 送信
        Transport t = new AWSJavaMailTransport(session, null);
        try {
            t.connect();
            t.sendMessage(msg, null);
        } finally {
            t.close();
        }
    }
    
    // 認証
    private static void verifyEmailAddress(AmazonSimpleEmailService ses, String address) {
        ListVerifiedEmailAddressesResult verifiedEmails = ses.listVerifiedEmailAddresses();
        if (verifiedEmails.getVerifiedEmailAddresses().contains(address)) return; 
        ses.verifyEmailAddress(new VerifyEmailAddressRequest().withEmailAddress(address));
    }
}

認証していない場合

認証メールを送信して認証することで対応可能とのこと

hostでリージョンのエンドポイントを指定する。

何も指定していないとus-east-1でしか送信していない感じに見える。